def __init__(self, res=None, name="Traceroute", stats=None): PacketList.__init__(self, res, name, stats) self.graphdef = None self.graphASres = 0 self.padding = 0 self.hloc = None self.nloc = None
def _update_supported_responses(self, pkt): self._unanswered_packets += PacketList([pkt]) answered, unanswered = self._unanswered_packets.sr() for _, resp in answered: ecu_resp = ECUResponse(session=self.current_session, security_level=self.current_security_level, responses=resp) if ecu_resp not in self._supported_responses: if self.verbose: print("[+] ", repr(ecu_resp)) self._supported_responses.append(ecu_resp) else: if self.verbose: print("[-] ", repr(ecu_resp)) self._unanswered_packets = unanswered
def read_all(self, count=-1): # type: (int) -> PacketList """Read a specific number or all packets from a candump file. :param count: Specify a specific number of packets to be read. All packets can be read by count=-1. :return: A PacketList object containing read CAN messages """ res = [] while count != 0: try: p = self.read_packet() if p is None: continue except EOFError: break count -= 1 res.append(p) return PacketList(res, name=os.path.basename(self.filename))
def defragment(plist): """defrag(plist) -> plist defragmented as much as possible """ frags = {} final = [] pos = 0 for p in plist: p._defrag_pos = pos pos += 1 if IP in p: ip = p[IP] if ip.frag != 0 or ip.flags & 1: ip = p[IP] uniq = (ip.id,ip.src,ip.dst,ip.proto) if uniq in frags: frags[uniq].append(p) else: frags[uniq] = [p] continue final.append(p) defrag = [] missfrag = [] for lst in frags.itervalues(): lst.sort(lambda x,y:cmp(x.frag, y.frag)) p = lst[0] if p.frag > 0: missfrag += lst continue p = p.copy() if Padding in p: del(p[Padding].underlayer.payload) ip = p[IP] if ip.len is None or ip.ihl is None: clen = len(ip.payload) else: clen = ip.len - (ip.ihl<<2) txt = Raw() for q in lst[1:]: if clen != q.frag<<3: if clen > q.frag<<3: warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q)) missfrag += lst txt = None break if q[IP].len is None or q[IP].ihl is None: clen += len(q[IP].payload) else: clen += q[IP].len - (q[IP].ihl<<2) if Padding in q: del(q[Padding].underlayer.payload) txt.add_payload(q[IP].payload.copy()) if txt is None: continue ip.flags &= ~1 # !MF del(ip.chksum) del(ip.len) p = p/txt p._defrag_pos = lst[-1]._defrag_pos defrag.append(p) defrag2=[] for p in defrag: q = p.__class__(str(p)) q._defrag_pos = p._defrag_pos defrag2.append(q) final += defrag2 final += missfrag final.sort(lambda x,y: cmp(x._defrag_pos, y._defrag_pos)) for p in final: del(p._defrag_pos) if hasattr(plist, "listname"): name = "Defragmented %s" % plist.listname else: name = "Defragmented" return PacketList(final, name=name)
def processTcpPacket(dumb,queue,print_counter,counter_val): logging.warning("In function : processTcpPacket") counter_create_issue= 0 lst=[] i=0 while 1: counter_create_issue = counter_create_issue + 1 #try: if True: if (queue.qsize != 0 ): lst.append(queue.get()) Packet=PacketList(lst,"Sniffed") pkt_type=get_packet_type(Packet[i]) #print " My packet type is " #print pkt_type if (pkt_type==SYNACK_NO): send_ack_packet(Packet[i]) send_bgp_open( Packet[i] ) elif (pkt_type==SYN_NO): #dumbi=0 send_syn_ack_packet(Packet[i]) elif (pkt_type==ACK_NO): dumbi = 0 elif (pkt_type==FIN): send_tcp_fin_set(Packet[i]) elif (pkt_type==CONT_FIN): send_tcp_fin_set(Packet[i]) elif (pkt_type==CONT_FIN_ACK): dumbi = 0 send_tcp_fin_set(Packet[i]) elif (pkt_type==CONT_PSH_ACK): send_ack_packet(Packet[i]) else : logging.warning("Received Packet with Flag set : " + str(pkt_type)) bgp_pkt_type=get_bgp_packet_type(Packet[i]) if (bgp_pkt_type==BGP_OPEN): logging.warning("Got a Bgp open") if host_info.has_key(Packet[i][IP].dst) == True: if host_info[Packet[i][IP].dst]['state'] == 0: # REMOVE COMMENT HERE send_bgp_open(Packet[i]) elif (bgp_pkt_type==BGP_KEEPALIVE): dumbi = 0 send_bgp_keepalive(Packet[i]) if True: Packet[i].seq=Packet[i].seq Packet[i].ack=int(Packet[i].ack)+19 send_bgp_update(Packet[i]) if counter_create_issue / 100 > 0: counter_create_issue= 0 send_bgp_open(Packet[i]) elif (bgp_pkt_type==BGP_UPDATE): dumbi=0 print "recv bgp update" send_bgp_update(Packet[i]) #recv_bgp_update(Packet[i]) elif (bgp_pkt_type==BGP_NOTIFY): dumbi=0 print "recv notify" send_tcp_syn_pkts(1,int(Packet[i].dport)+2,BURST_TIMER) #recv_bgp_notify(Packet[i]) elif (bgp_pkt_type==None): dumbi = 0 else : logging.warning("Received Packet with Flag set : " + str(bgp_pkt_type)) lst.pop()
def __sr_loop(srfunc, # type: Callable[..., Tuple[SndRcvList, PacketList]] pkts, # type: _PacketIterable prn=lambda x: x[1].summary(), # type: Callable[[QueryAnswer], Any] # noqa: E501 prnfail=lambda x: x.summary(), # type: Callable[[Packet], Any] inter=1, # type: int timeout=None, # type: Optional[int] count=None, # type: Optional[int] verbose=None, # type: Optional[int] store=1, # type: int *args, # type: Any **kargs # type: Any ): # type: (...) -> Tuple[SndRcvList, PacketList] n = 0 r = 0 ct = conf.color_theme if verbose is None: verbose = conf.verb parity = 0 ans = [] # type: List[QueryAnswer] unans = [] # type: List[Packet] if timeout is None: timeout = min(2 * inter, 5) try: while True: parity ^= 1 col = [ct.even, ct.odd][parity] if count is not None: if count == 0: break count -= 1 start = time.time() if verbose > 1: print("\rsend...\r", end=' ') res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=True, *args, **kargs) # noqa: E501 n += len(res[0]) + len(res[1]) r += len(res[0]) if verbose > 1 and prn and len(res[0]) > 0: msg = "RECV %i:" % len(res[0]) print("\r" + ct.success(msg), end=' ') for p in res[0]: print(col(prn(p))) print(" " * len(msg), end=' ') if verbose > 1 and prnfail and len(res[1]) > 0: msg = "fail %i:" % len(res[1]) print("\r" + ct.fail(msg), end=' ') for p in res[1]: print(col(prnfail(p))) print(" " * len(msg), end=' ') if verbose > 1 and not (prn or prnfail): print("recv:%i fail:%i" % tuple(map(len, res[:2]))) if store: ans += res[0] unans += res[1] end = time.time() if end - start < inter: time.sleep(inter + start - end) except KeyboardInterrupt: pass if verbose and n > 0: print(ct.normal("\nSent %i packets, received %i packets. %3.1f%% hits." % (n, r, 100.0 * r / n))) # noqa: E501 return SndRcvList(ans), PacketList(unans)
def __init__(self, res=None, name="Dot11List", stats=None): if stats is None: stats = conf.stats_dot11_protocols PacketList.__init__(self, res, name, stats)
def get_threading_plist(): temp = Vault.__threading_packet_list Vault.__threading_packet_list = PacketList() return temp
def __init__(self, pks, # type: SuperSocket pkt, # type: _PacketIterable timeout=None, # type: Optional[int] inter=0, # type: int verbose=None, # type: Optional[int] chainCC=False, # type: bool retry=0, # type: int multi=False, # type: bool rcv_pks=None, # type: Optional[SuperSocket] prebuild=False, # type: bool _flood=None, # type: Optional[Tuple[int, Callable[[], None]]] # noqa: E501 threaded=False, # type: bool session=None # type: Optional[_GlobSessionType] ): # type: (...) -> None # Instantiate all arguments if verbose is None: verbose = conf.verb if conf.debug_match: debug.recv = PacketList([], "Received") debug.sent = PacketList([], "Sent") debug.match = SndRcvList([], "Matched") self.nbrecv = 0 self.ans = [] # type: List[QueryAnswer] self.pks = pks self.rcv_pks = rcv_pks or pks self.inter = inter self.verbose = verbose self.chainCC = chainCC self.multi = multi self.timeout = timeout self.session = session # Instantiate packet holders if _flood: self.tobesent = pkt # type: Union[_PacketIterable, SetGen[Packet]] self.notans = _flood[0] else: if isinstance(pkt, types.GeneratorType) or prebuild: self.tobesent = list(pkt) self.notans = len(self.tobesent) else: self.tobesent = ( SetGen(pkt) if not isinstance(pkt, Gen) else pkt ) self.notans = self.tobesent.__iterlen__() if retry < 0: autostop = retry = -retry else: autostop = 0 if timeout is not None and timeout < 0: self.timeout = None while retry >= 0: self.hsent = {} # type: Dict[bytes, List[Packet]] if threaded or _flood: # Send packets in thread. # https://github.com/secdev/scapy/issues/1791 snd_thread = Thread( target=self._sndrcv_snd ) snd_thread.setDaemon(True) # Start routine with callback self._sndrcv_rcv(snd_thread.start) # Ended. Let's close gracefully if _flood: # Flood: stop send thread _flood[1]() snd_thread.join() else: self._sndrcv_rcv(self._sndrcv_snd) if multi: remain = [ p for p in itertools.chain(*six.itervalues(self.hsent)) if not hasattr(p, '_answered') ] else: remain = list(itertools.chain(*six.itervalues(self.hsent))) if autostop and len(remain) > 0 and \ len(remain) != len(self.tobesent): retry = autostop self.tobesent = remain if len(self.tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent = PacketList(remain[:], "Sent") debug.match = SndRcvList(self.ans[:]) # Clean the ans list to delete the field _answered if multi: for snd, _ in self.ans: if hasattr(snd, '_answered'): del snd._answered if verbose: print( "\nReceived %i packets, got %i answers, " "remaining %i packets" % ( self.nbrecv + len(self.ans), len(self.ans), self.notans ) ) self.ans_result = SndRcvList(self.ans) self.unans_result = PacketList(remain, "Unanswered")
def sndrcvflood(pks, pkt, inter=0, verbose=None, chainCC=False, store_unanswered=True, process=None, timeout=None): if not verbose: verbose = conf.verb listable = (isinstance(pkt, Packet) and pkt.__iterlen__() == 1) or isinstance(pkt, list) # noqa: E501 tobesent = pkt use_prn_mode = False _storage_policy = None if process is not None: use_prn_mode = True _storage_policy = lambda x, y: process(x, y) stopevent = threading.Event() count_packets = six.moves.queue.Queue() hsent = {} timessent = {} if listable else None def send_in_loop(tobesent, stopevent, count_packets=count_packets): """Infinite generator that produces the same packet until stopevent is triggered.""" # noqa: E501 while True: for p in tobesent: if stopevent.is_set(): return count_packets.put(0) yield p infinite_gen = send_in_loop(tobesent, stopevent) def _timeout(timeout): stopevent.wait(timeout) stopevent.set() timeout_thread = threading.Thread(target=_timeout, args=(timeout, )) timeout_thread.setDaemon(True) timeout_thread.start() # We don't use _sndrcv_snd verbose (it messes the logs up as in a thread that ends after receiving) # noqa: E501 thread = threading.Thread(target=_sndrcv_snd, args=(pks, None, inter, False, infinite_gen, hsent, timessent, stopevent)) thread.setDaemon(True) thread.start() hsent, ans, nbrecv, notans = _sndrcv_rcv(pks, hsent, stopevent, 0, len(tobesent), verbose, chainCC, False, _storage_policy=_storage_policy) thread.join() # Restore time_sent to original packets if listable: i = 0 for p in (pkt if isinstance(pkt, list) else [pkt]): p.sent_time = timessent[i] i += 1 if process is not None: ans = [(x, process(y)) for (x, y) in ans] # Apply process if store_unanswered: if use_prn_mode: remain = [ process(x, None) for x in itertools.chain(*six.itervalues(hsent)) ] # noqa: E501 else: remain = list(itertools.chain(*six.itervalues(hsent))) if verbose: print( "\nReceived %i packets, got %i answers, remaining %i packets. Sent a total of %i packets." % (nbrecv + len(ans), len(ans), notans, count_packets.qsize())) # noqa: E501 count_packets.empty() del count_packets ans_result = ans if use_prn_mode else SndRcvList(ans) unans_result = remain if use_prn_mode else ( None if not store_unanswered else PacketList(remain, "Unanswered") ) # noqa: E501 return ans_result, unans_result
def __gen_send(s, # type: SuperSocket x, # type: _PacketIterable inter=0, # type: int loop=0, # type: int count=None, # type: Optional[int] verbose=None, # type: Optional[int] realtime=False, # type: bool return_packets=False, # type: bool *args, # type: Any **kargs # type: Any ): # type: (...) -> Optional[PacketList] """ An internal function used by send/sendp to actually send the packets, implement the send logic... It will take care of iterating through the different packets """ if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 sent_packets = PacketList() if return_packets else None p = None try: while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0 + float(p.time) - ct if st > 0: time.sleep(st) else: dt0 = ct - float(p.time) s.send(p) if sent_packets is not None: sent_packets.append(p) n += 1 if verbose: os.write(1, b".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass finally: try: cast(Packet, x).sent_time = cast(Packet, p).sent_time except AttributeError: pass if verbose: print("\nSent %i packets." % n) return sent_packets
def __gen_send_mod(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, port_random_flag=False, size_random_flag=False, src_random_flag=False, specific_subnet_random=False, source_addr='Default', pcktcount=None, log=None, *args, **kargs): # noqa: E501 totaltimeelapsedns = 0.0 totaltimeelapseds = 0.0 if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 if return_packets: sent_packets = PacketList() try: startVelkoSec = time.time() while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0 + p.time - ct if st > 0: time.sleep(st) else: dt0 = ct - p.time if (p.proto == 1): p.type = int(random.randrange(0, 255)) p.code = int(random.randrange(0, 255)) if (port_random_flag): targ_port = int(random.randrange(0, 65535)) p.dport = targ_port if (size_random_flag): packet_size = int( random.randrange(0, 6550) ) # 7 I removed 7 because there seems to be some boundary crossing(bleeding) p.add_payload((str(_generatePacket(packet_size))).encode()) if (src_random_flag): p.src = socket.inet_ntoa( struct.pack('>I', random.randint(1, 0xffffffff))) elif (specific_subnet_random): try: subnet = IPv4Network(source_addr) bits = random.getrandbits(subnet.max_prefixlen - subnet.prefixlen) p.src = str(IPv4Address(subnet.network_address + bits)) except ValueError: print("Something is wrong!sendrcv ") if ((n % int(pcktcount)) == 0): endVelkoSec = time.time() totaltimeelapseds += (endVelkoSec - startVelkoSec) print("\n+++TIMESTAMP+++\nTimestamp taken after:", n, "packets") #print('{:%Y-%m-%d_%H:%M:%S}'.format(datetime.datetime.now())+"\n") print((datetime.datetime.now() ).strftime('%Y-%m-%d %H:%M:%S.%f')[:-2] + " (UTC)\n") print("TIME(s): ", (endVelkoSec - startVelkoSec)) print("TIME(ns): ", (endVelkoSec - startVelkoSec) * 1000000000) print("TOTAL TIME(s): ", totaltimeelapseds) print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++\n" ) #LOG SECTION # file_name=log # f = open(file_name, 'a+') # f.write("\n+++TIMESTAMP+++\nTimestamp taken after: "+str(n)+"\n") # f.write(datetime.datetime.utcnow().strftime('%Y-%m-%d %H-%M-%S_%f')[:-2]+" (UTC)\n") # f.write("TIME(ns): "+str((endVelkoSec - startVelkoSec)*1000000000)+"\n") # f.write("TIME(s): "+ str(endVelkoSec-startVelkoSec)+"\n") # f.write("TOTAL TIME ELAPSED(s): "+str(totaltimeelapseds)+"\n") # f.write("\n===WholePacket===\n") # tmp=p.show(dump=True) # f.write(str(tmp)) # f.close() # TODO: Should log only if log is activated #log_packet(p,log) #END LOG SECTION s.send(p) if (p.proto == 1): print( datetime.datetime.utcnow().strftime( '%Y-%m-%d_%H-%M-%S_%f')[:-2] + "(UTC)\t", "proto", p.proto, "\tsrc", p.src, "\tdst", p.dst, "\tcode", p.code, "\ttype", p.type, "\tLength(b)", len(p)) else: print( datetime.datetime.utcnow().strftime( '%Y-%m-%d_%H-%M-%S_%f')[:-2] + "(UTC)\t", "proto", p.proto, "\tsrc", p.src, "\tsport", p.sport, "\tdst", p.dst, "\tdport", p.dport, "\tLength(b)", len(p)) # time.sleep(5) if return_packets: sent_packets.append(p) n += 1 if verbose: os.write(1, b".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass if verbose: print("\nSent %i packets." % n) if return_packets: return sent_packets
def sndrcv(pks, pkt, timeout=None, inter=0, verbose=None, chainCC=False, retry=0, multi=False, rcv_pks=None, store_unanswered=True, process=None, prebuild=False): """Scapy raw function to send a packet and receive its answer. WARNING: This is an internal function. Using sr/srp/sr1/srp is more appropriate in many cases. """ if verbose is None: verbose = conf.verb use_prn_mode = False _storage_policy = None if process is not None: use_prn_mode = True _storage_policy = lambda x, y: process(x, y) debug.recv = PacketList([], "Unanswered") debug.sent = PacketList([], "Sent") debug.match = SndRcvList([]) nbrecv = 0 ans = [] listable = (isinstance(pkt, Packet) and pkt.__iterlen__() == 1) or isinstance(pkt, list) # noqa: E501 # do it here to fix random fields, so that parent and child have the same if isinstance(pkt, types.GeneratorType) or prebuild: tobesent = [p for p in pkt] notans = len(tobesent) else: tobesent = SetGen(pkt) if not isinstance(pkt, Gen) else pkt notans = tobesent.__iterlen__() if retry < 0: autostop = retry = -retry else: autostop = 0 while retry >= 0: if timeout is not None and timeout < 0: timeout = None stopevent = threading.Event() hsent = {} timessent = {} if listable else None _sndrcv_snd(pks, timeout, inter, verbose, tobesent, hsent, timessent, stopevent) hsent, newans, nbrecv, notans = _sndrcv_rcv( (rcv_pks or pks), hsent, stopevent, nbrecv, notans, verbose, chainCC, multi, _storage_policy=_storage_policy, ) ans.extend(newans) # Restore time_sent to original packets if listable: i = 0 for p in (pkt if isinstance(pkt, list) else [pkt]): p.sent_time = timessent[i] i += 1 if store_unanswered: remain = list(itertools.chain(*six.itervalues(hsent))) if multi: remain = [p for p in remain if not hasattr(p, '_answered')] if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break else: remain = [] retry -= 1 if conf.debug_match: debug.sent = PacketList(remain[:], "Sent") debug.match = SndRcvList(ans[:]) # Clean the ans list to delete the field _answered if multi: for snd, _ in ans: if hasattr(snd, '_answered'): del snd._answered if verbose: print("\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv + len(ans), len(ans), notans)) # noqa: E501 if store_unanswered and use_prn_mode: remain = [process(x, None) for x in remain] ans_result = ans if use_prn_mode else SndRcvList(ans) unans_result = remain if use_prn_mode else ( None if not store_unanswered else PacketList(remain, "Unanswered") ) # noqa: E501 return ans_result, unans_result
class Escapy: """ Insanely good wrapper for scapy. Aids in asynchronous sniffing and extracting data in scapy.packets """ __packet_values = (int, float, str, bytes, bool, list, tuple, set, dict, type(None)) __explicit_layers = [HTTPRequest, HTTPResponse] __cap = PacketList() @staticmethod def async_sniff(action=None, count=0, store=False): """ Sniffs packets asynchronously """ # prepare for a fresh run (threading safety) Escapy.__cap = PacketList # enable monitor mode on linux based systems monitor_mode = not os_name == "nt" logger.info(f"Monitor Mode: [{monitor_mode}]") Escapy.__cap = AsyncSniffer(prn=action, monitor=monitor_mode, count=count, store=store) Escapy.__cap.start() @staticmethod def stop(): """ Stop async_sniff() """ Escapy.__cap.stop() Escapy.__cap.join() @staticmethod def get_cap(): """ Returns the scapy async_sniff "thread" """ return Escapy.__cap @staticmethod def load_cap(file_name) -> PacketList: """ Load .cap into scapy.plist """ try: cap = rdpcap(f"{CAP_PATH}{file_name}{CAP_EXTENSION}") logger.info(f"\"{file_name}{CAP_EXTENSION}\" loaded") return cap except FileNotFoundError as error: logger.warning(f"{type(error).__name__}: \"{format(error)}\"") @staticmethod def save_cap(file_name, cap) -> bool: """ Save scapy.plist into .cap """ try: wrpcap(f"{CAP_PATH}{file_name}{CAP_EXTENSION}", cap) logger.info(f"\"{file_name}{CAP_EXTENSION}\" saved") except FileNotFoundError as error: logger.warning(f"{type(error).__name__}: \"{format(error)}\"") @staticmethod def convert_packet(packet, *args, explicit_layers=[]) -> OrderedDict: """ Converts "scapy.layers.l2.Ether" to a dictionary form factor """ explicit_layers = Escapy.__explicit_layers + explicit_layers packet_dict = OrderedDict() count = 0 # default scapy layers while (layer := packet.getlayer(count)): count += 1 # if layer is not required if len(args) != 0 and layer.name not in args: continue # if layer returns no data if (layer_dict := Escapy.__layer_dict(layer)) is None: continue # concatenate dictionaries packet_dict = {**packet_dict, **layer_dict}
def sndrcv(pks, pkt, timeout=None, inter=0, verbose=None, chainCC=False, retry=0, multi=False, rcv_pks=None, store_unanswered=True, process=None, prebuild=False): """Scapy raw function to send a packet and receive its answer. WARNING: This is an internal function. Using sr/srp/sr1/srp is more appropriate in many cases. pks: SuperSocket instance to send/receive packets pkt: the packet to send rcv_pks: if set, will be used instead of pks to receive packets. packets will still # noqa: E501 be sent through pks nofilter: put 1 to avoid use of BPF filters retry: if positive, how many times to resend unanswered packets if negative, how many times to retry when no more packets are answered # noqa: E501 timeout: how much time to wait after the last packet has been sent verbose: set verbosity level multi: whether to accept multiple answers for the same stimulus store_unanswered: whether to store not-answered packets or not. Default True. # noqa: E501 setting it to False will increase speed, and will return None # noqa: E501 as the unans list. process: if specified, only result from process(pkt) will be stored. the function should follow the following format: lambda sent, received: (func(sent), func2(received)) if the packet is unanswered, `received` will be None. if `store_unanswered` is False, the function won't be called on un-answered packets. # noqa: E501 prebuild: pre-build the packets before starting to send them. Default to False. Automatically used # noqa: E501 when a generator is passed as the packet """ if verbose is None: verbose = conf.verb use_prn_mode = False _storage_policy = None if process is not None: use_prn_mode = True _storage_policy = lambda x, y: process(x, y) debug.recv = PacketList([], "Unanswered") debug.sent = PacketList([], "Sent") debug.match = SndRcvList([]) nbrecv = 0 ans = [] listable = (isinstance(pkt, Packet) and pkt.__iterlen__() == 1) or isinstance(pkt, list) # noqa: E501 # do it here to fix random fields, so that parent and child have the same if isinstance(pkt, types.GeneratorType) or prebuild: tobesent = [p for p in pkt] notans = len(tobesent) else: tobesent = SetGen(pkt) if not isinstance(pkt, Gen) else pkt notans = tobesent.__iterlen__() if retry < 0: autostop = retry = -retry else: autostop = 0 while retry >= 0: if timeout is not None and timeout < 0: timeout = None stopevent = threading.Event() hsent = {} timessent = {} if listable else None thread = threading.Thread( target=_sndrcv_snd, args=(pks, timeout, inter, verbose, tobesent, hsent, timessent, stopevent), # noqa: E501 ) thread.setDaemon(True) thread.start() hsent, newans, nbrecv, notans = _sndrcv_rcv( (rcv_pks or pks), hsent, stopevent, nbrecv, notans, verbose, chainCC, multi, # noqa: E501 _storage_policy=_storage_policy, ) thread.join() ans.extend(newans) # Restore time_sent to original packets if listable: i = 0 for p in (pkt if isinstance(pkt, list) else [pkt]): p.sent_time = timessent[i] i += 1 if store_unanswered: remain = list(itertools.chain(*six.itervalues(hsent))) if multi: remain = [p for p in remain if not hasattr(p, '_answered')] if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break else: remain = [] retry -= 1 if conf.debug_match: debug.sent = PacketList(remain[:], "Sent") debug.match = SndRcvList(ans[:]) # Clean the ans list to delete the field _answered if multi: for snd, _ in ans: if hasattr(snd, '_answered'): del snd._answered if verbose: print("\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv + len(ans), len(ans), notans)) # noqa: E501 if store_unanswered and use_prn_mode: remain = [process(x, None) for x in remain] ans_result = ans if use_prn_mode else SndRcvList(ans) unans_result = remain if use_prn_mode else ( None if not store_unanswered else PacketList(remain, "Unanswered") ) # noqa: E501 return ans_result, unans_result
def get_saving_plist(): temp = Vault.__saving_packet_list Vault.__saving_packet_list = PacketList() return temp
def toPacketList(self): return PacketList(self.lst, "Sniffed")
class Ecu(object): """An Ecu object can be used to * track the states of an Ecu. * to log all modification to an Ecu. * to extract supported responses of a real Ecu. Example: >>> print("This ecu logs, tracks and creates supported responses") >>> my_virtual_ecu = Ecu() >>> my_virtual_ecu.update(PacketList([...])) >>> my_virtual_ecu.supported_responses >>> print("Another ecu just tracks") >>> my_tracking_ecu = Ecu(logging=False, store_supported_responses=False) >>> my_tracking_ecu.update(PacketList([...])) >>> print("Another ecu just logs all modifications to it") >>> my_logging_ecu = Ecu(verbose=False, store_supported_responses=False) >>> my_logging_ecu.update(PacketList([...])) >>> my_logging_ecu.log >>> print("Another ecu just creates supported responses") >>> my_response_ecu = Ecu(verbose=False, logging=False) >>> my_response_ecu.update(PacketList([...])) >>> my_response_ecu.supported_responses Parameters to initialize an Ecu object :param logging: Turn logging on or off. Default is on. :param verbose: Turn tracking on or off. Default is on. :param store_supported_responses: Create a list of supported responses if True. :param lookahead: Configuration for lookahead when computing supported responses """ # noqa: E501 def __init__(self, logging=True, verbose=True, store_supported_responses=True, lookahead=10): # type: (bool, bool, bool, int) -> None self.state = EcuState() self.verbose = verbose self.logging = logging self.store_supported_responses = store_supported_responses self.lookahead = lookahead self.log = defaultdict(list) # type: Dict[str, List[Any]] self.__supported_responses = list() # type: List[EcuResponse] self.__unanswered_packets = PacketList() def reset(self): # type: () -> None """ Resets the internal state to a default EcuState. """ self.state = EcuState(session=1) def update(self, p): # type: (Union[Packet, PacketList]) -> None """ Processes a Packet or a list of Packets, according to the chosen configuration. :param p: Packet or list of Packets """ if isinstance(p, PacketList): for pkt in p: self.update(pkt) elif not isinstance(p, Packet): raise TypeError("Provide a Packet object for an update") else: self.__update(p) def __update(self, pkt): # type: (Packet) -> None """ Processes a Packet according to the chosen configuration. :param pkt: Packet to be processed """ if self.verbose: print(repr(self), repr(pkt)) if self.logging: self.__update_log(pkt) self.__update_supported_responses(pkt) def __update_log(self, pkt): # type: (Packet) -> None """ Checks if a packet or a layer of this packet supports the function `get_log`. If `get_log` is supported, this function will be executed and the returned log information is stored in the intern log of this Ecu object. :param pkt: A Packet to be processed for log information. """ for layer in pkt.layers(): if not hasattr(layer, "get_log"): continue try: log_key, log_value = layer.get_log(pkt) except TypeError: log_key, log_value = layer.get_log.im_func(pkt) self.log[log_key].append((pkt.time, log_value)) def __update_supported_responses(self, pkt): # type: (Packet) -> None """ Stores a given packet as supported response, if a matching request packet is found in a list of the latest unanswered packets. For performance improvements, this list of unanswered packets only contains a fixed number of packets, defined by the `lookahead` parameter of this Ecu. :param pkt: Packet to be processed. """ self.__unanswered_packets.append(pkt) reduced_plist = self.__unanswered_packets[-self.lookahead:] answered, unanswered = reduced_plist.sr(lookahead=self.lookahead) self.__unanswered_packets = unanswered for req, resp in answered: added = False current_state = copy.copy(self.state) EcuState.get_modified_ecu_state(resp, req, self.state, True) if not self.store_supported_responses: continue for sup_resp in self.__supported_responses: if resp == sup_resp.key_response: if sup_resp.states is not None and \ self.state not in sup_resp.states: sup_resp.states.append(current_state) added = True break if added: continue ecu_resp = EcuResponse(current_state, responses=resp) if self.verbose: print("[+] ", repr(ecu_resp)) self.__supported_responses.append(ecu_resp) @staticmethod def sort_key_func(resp): # type: (EcuResponse) -> Tuple[bool, int, int, int] """ This sorts responses in the following order: 1. Positive responses first 2. Lower ServiceIDs first 3. Less supported states first 4. Longer (more specific) responses first :param resp: EcuResponse to be sorted :return: Tuple as sort key """ first_layer = cast(Packet, resp.key_response[0]) # type: ignore service = orb(bytes(first_layer)[0]) return (service == 0x7f, service, 0xffffffff - len(resp.states or []), 0xffffffff - len(resp.key_response)) @property def supported_responses(self): # type: () -> List[EcuResponse] """ Returns a sorted list of supported responses. The sort is done in a way to provide the best possible results, if this list of supported responses is used to simulate an real world Ecu with the EcuAnsweringMachine object. :return: A sorted list of EcuResponse objects """ self.__supported_responses.sort(key=self.sort_key_func) return self.__supported_responses @property def unanswered_packets(self): # type: () -> PacketList """ A list of all unanswered packets, which were processed by this Ecu object. :return: PacketList of unanswered packets """ return self.__unanswered_packets def __repr__(self): # type: () -> str return repr(self.state) @staticmethod def extend_pkt_with_logging(cls): # type: (Type[Packet]) -> Callable[[Callable[[Packet], Tuple[str, Any]]], None] # noqa: E501 """ Decorator to add a function as 'get_log' method to a given class. This allows dynamic modifications and additions to a protocol. :param cls: A packet class to be modified :return: Decorator function """ def decorator_function(f): # type: (Callable[[Packet], Tuple[str, Any]]) -> None setattr(cls, "get_log", f) return decorator_function
def toPacketList(self): # type: () -> PacketList if self._supersession: return PacketList(self._supersession.lst, "Sniffed") else: return PacketList(self.lst, "Sniffed")
def __init__(self, pks, pkt, timeout=None, inter=0, verbose=None, chainCC=False, retry=0, multi=False, rcv_pks=None, prebuild=False, _flood=None): # Instantiate all arguments if verbose is None: verbose = conf.verb if conf.debug_match: debug.recv = PacketList([], "Received") debug.sent = PacketList([], "Sent") debug.match = SndRcvList([], "Matched") self.nbrecv = 0 self.ans = [] self.pks = pks self.rcv_pks = rcv_pks or pks self.inter = inter self.verbose = verbose self.chainCC = chainCC self.multi = multi self.timeout = timeout # Instantiate packet holders if _flood: self.tobesent = pkt self.notans = _flood[0] else: if isinstance(pkt, types.GeneratorType) or prebuild: self.tobesent = [p for p in pkt] self.notans = len(self.tobesent) else: self.tobesent = (SetGen(pkt) if not isinstance(pkt, Gen) else pkt) self.notans = self.tobesent.__iterlen__() if retry < 0: autostop = retry = -retry else: autostop = 0 if timeout is not None and timeout < 0: self.timeout = None while retry >= 0: self.hsent = {} # Send packets in thread. # https://github.com/secdev/scapy/issues/1791 snd_thread = Thread(target=self._sndrcv_snd) snd_thread.setDaemon(True) # Start routine with callback self._sndrcv_rcv(snd_thread.start) # Ended. Let's close gracefully if _flood: # Flood: stop send thread _flood[1]() snd_thread.join() if multi: remain = [ p for p in itertools.chain(*six.itervalues(self.hsent)) if not hasattr(p, '_answered') ] else: remain = list(itertools.chain(*six.itervalues(self.hsent))) if autostop and len(remain) > 0 and \ len(remain) != len(self.tobesent): retry = autostop self.tobesent = remain if len(self.tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent = PacketList(remain[:], "Sent") debug.match = SndRcvList(self.ans[:]) # Clean the ans list to delete the field _answered if multi: for snd, _ in self.ans: if hasattr(snd, '_answered'): del snd._answered if verbose: print("\nReceived %i packets, got %i answers, " "remaining %i packets" % (self.nbrecv + len(self.ans), len(self.ans), self.notans)) self.ans_result = SndRcvList(self.ans) self.unans_result = PacketList(remain, "Unanswered")
def get_capture(self, expected_count=None, remark=None, timeout=1, filter_out_fn=is_ipv6_misc): """ Get captured packets :param expected_count: expected number of packets to capture, if None, then self.test.packet_count_for_dst_pg_idx is used to lookup the expected count :param remark: remark printed into debug logs :param timeout: how long to wait for packets :param filter_out_fn: filter applied to each packet, packets for which the filter returns True are removed from capture :returns: iterable packets """ remaining_time = timeout capture = None name = self.name if remark is None else "%s (%s)" % (self.name, remark) based_on = "based on provided argument" if expected_count is None: expected_count = \ self.test.get_packet_count_for_if_idx(self.sw_if_index) based_on = "based on stored packet_infos" if expected_count == 0: raise Exception( "Internal error, expected packet count for %s is 0!" % name) self.test.logger.debug("Expecting to capture %s (%s) packets on %s" % (expected_count, based_on, name)) while remaining_time > 0: before = time.time() capture = self._get_capture(remaining_time, filter_out_fn) elapsed_time = time.time() - before if capture: if len(capture.res) == expected_count: # bingo, got the packets we expected return capture elif len(capture.res) > expected_count: self.test.logger.error( ppc("Unexpected packets captured:", capture)) break else: self.test.logger.debug("Partial capture containing %s " "packets doesn't match expected " "count %s (yet?)" % (len(capture.res), expected_count)) elif expected_count == 0: # bingo, got None as we expected - return empty capture return PacketList() remaining_time -= elapsed_time if capture: self.generate_debug_aid("count-mismatch") if len(capture) > 0 and 0 == expected_count: rem = f"\n{remark}" if remark else "" raise UnexpectedPacketError( capture[0], f"\n({len(capture)} packets captured in total){rem}") raise Exception("Captured packets mismatch, captured %s packets, " "expected %s packets on %s" % (len(capture.res), expected_count, name)) else: raise Exception("No packets captured on %s" % name)
class Vault: __runtime_name = None __saving = False __threading_packet_list = PacketList() __saving_packet_list = PacketList() __mapping = Counter() __packet_count = 0 __session_dict = {} __session_header = [] __flagged_dict = {} __carved_files = [] @staticmethod def set_runtime_name(runtime_name): Vault.__runtime_name = runtime_name @staticmethod def get_runtime_name(): return Vault.__runtime_name @staticmethod def set_saving(saving): Vault.__saving = saving @staticmethod def get_saving(): return Vault.__saving @staticmethod def refresh(): Vault.__threading_packet_list = PacketList() Vault.__mapping = Counter() Vault.__packet_count = 0 Vault.__session_dict = {} Vault.__session_header = [] Vault.__flagged_dict = {} Vault.__carved_files = [] @staticmethod def update_mapping(packet): try: tmp = sorted([packet[0][1].src, packet[0][1].dst]) key = f"{tmp[0]},{tmp[1]}" Vault.__mapping.update([key]) logger.debug(f"Packet #{sum(Vault.__mapping.values())}:" + f"{packet[0][1].src} ==> {packet[0][1].dst}") except AttributeError: tmp = sorted([packet[0][0].src, packet[0][0].dst]) key = f"{tmp[0]},{tmp[1]}" Vault.__mapping.update([key]) logger.debug(f"Packet #{sum(Vault.__mapping.values())}:" + f"{packet[0][0].src} ==> {packet[0][0].dst}") @staticmethod def get_mapping(): ip_list = [] for key in Vault.__mapping: ip1, ip2 = key.split(',') ip_list.append(ip1) ip_list.append(ip2) return Vault.__mapping, list(set(ip_list)) @staticmethod def plist_append(packet): # increment total packet count Vault.__packet_count += 1 Vault.__threading_packet_list.append(packet) if Vault.__saving: Vault.__saving_packet_list.append(packet) @staticmethod def get_threading_plist(): temp = Vault.__threading_packet_list Vault.__threading_packet_list = PacketList() return temp @staticmethod def get_saving_plist(): temp = Vault.__saving_packet_list Vault.__saving_packet_list = PacketList() return temp @staticmethod def get_sessions(reset=False): if not reset: return Vault.__session_dict temp = Vault.__session_dict Vault.__session_dict = {} return temp @staticmethod def add_session(stream_dict): for header, plist in stream_dict.items(): Vault.__session_header += [header] if header not in\ Vault.__session_header else [] Vault.__session_dict[header] = Vault.__session_dict[header] +\ plist if header in Vault.__session_dict else plist @staticmethod def get_session_headers(): return Vault.__session_header @staticmethod def get_total_packet_count(): return Vault.__packet_count @staticmethod def get_flagged() -> dict: return Vault.__flagged_dict @staticmethod def set_flagged(flagged_dict): Vault.__flagged_dict.update(flagged_dict) @staticmethod def add_carved_file(session_header, timestamp, filename, cont_type): Vault.__carved_files.append( (session_header, timestamp, filename, cont_type)) @staticmethod def get_carved_files() -> list: return Vault.__carved_files
def ip_defragment(plist): """defrag(plist) -> plist defragmented as much as possible """ frags = defaultdict(lambda: []) final = [] pos = 0 for p in plist: p._defrag_pos = pos pos += 1 if IP in p: ip = p[IP] if ip.frag != 0 or ip.flags & 1: ip = p[IP] uniq = (ip.id, ip.src, ip.dst, ip.proto) frags[uniq].append(p) continue final.append(p) pbar = tqdm(total=len(frags), desc="IP defrag(1/2) ") defrag = [] missfrag = [] for lst in six.itervalues(frags): pbar.update(1) lst.sort(key=lambda x: x.frag) p = lst[0] lastp = lst[-1] if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing missfrag += lst continue p = p.copy() if conf.padding_layer in p: del (p[conf.padding_layer].underlayer.payload) ip = p[IP] if ip.len is None or ip.ihl is None: clen = len(ip.payload) else: clen = ip.len - (ip.ihl << 2) txt = conf.raw_layer() for q in lst[1:]: if clen != q.frag << 3: # Wrong fragmentation offset if clen > q.frag << 3: warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag << 3, p, txt, q)) missfrag += lst break if q[IP].len is None or q[IP].ihl is None: clen += len(q[IP].payload) else: clen += q[IP].len - (q[IP].ihl << 2) if conf.padding_layer in q: del (q[conf.padding_layer].underlayer.payload) txt.add_payload(q[IP].payload.copy()) else: ip.flags &= ~1 # !MF del (ip.chksum) del (ip.len) p = p / txt p._defrag_pos = max(x._defrag_pos for x in lst) defrag.append(p) pbar.close() defrag2 = [] for p in tqdm(defrag, desc="IP defrag(2/2) "): q = p.__class__(raw(p)) q._defrag_pos = p._defrag_pos defrag2.append(q) final += defrag2 final += missfrag final.sort(key=lambda x: x._defrag_pos) for p in final: del (p._defrag_pos) if hasattr(plist, "listname"): name = "Defragmented %s" % plist.listname else: name = "Defragmented" return PacketList(final, name=name)
deserialized_data = json.loads(data) if not re.search(flag_re, deserialized_data['Description']): new_packets.append(packet) continue deserialized_data['Description'] = args.flag new_json = json.dumps(deserialized_data, indent=4).encode() new_data = xor_data(new_json, key) new_length = xor_data(key, len(new_data).to_bytes(2, 'big')) new_payload = key + new_length + new_data # checksum isn't validated by scapy upon rebuilt unless the property is missing del packet['IP'].len del packet['IP'].chksum del packet['TCP'].chksum raw_payload.load = new_payload packet['TCP'].payload = raw_payload packet['TCP'].explicit = tcp_packet.explicit new_packet = l2.Ether(packet.build()) new_packet['TCP'].time = tcp_packet.time new_packet.time = packet.time new_packets.append(new_packet) else: new_packets.append(packet) new_plist = PacketList(new_packets) wrpcap(args.output, new_plist) print( f"Dumped the modified capture to {args.output}; be sure to verify with ctf-solve.py!" )
class Conversation(object): def __init__(self, packets, localport=50002, remoteport=4172, isUDP=True): ''' Initialise a conversation from a pcap file or a list otherwise obtained from scapy using scapy.rdpcap (also available as udpanal.rdpcap). Args: * packets - either string representing relative or absolute filename for pcap file or PacketList object returned by rdpcap * localport - the UDP port you communicated from * remoteport - the UDP port you are communicating with * isUDP - for future use when TCP & SCTP are also implemented ''' if type(packets) == type(''): pktlist = rdpcap(packets) elif type(PacketList()) == type(packets): pktlist = packets # re-initialise, take the penalty to kill that annoying 'filter multiplicity) else: self = packets self.lport = localport self.rport = remoteport if isUDP: pktlist = pktlist.filter(lambda x: x.haslayer(UDP)) pktlist = pktlist.filter( lambda x: x.getlayer(UDP).dport == self.lport or x.getlayer( UDP).sport == self.lport or x.getlayer(UDP).dport == self. rport or x.getlayer(UDP).sport == self.rport) self.pktlist = PacketList(pktlist) self.count = len(self.pktlist) return def __getitem__(self, y): re def fromLocal( self, asConvo=True ): # asConvo = False just returns packetlist which is more efficient. ''' Returns a conversation object or PacketList containing only packets sent from the local port. It optionally takes an argument which if true returns the result as a conversation object or a filtered PacketList object (for speed or list customisation before creating conversation). ''' m = self.pktlist.filter(lambda x: x[UDP].sport == self.lport) if asConvo: return Conversation(m) else: return m def fromRemote(self, asConvo=True): ''' Works as fromLocal, but packets coming from the remote side. ''' m = self.pktlist.filter(lambda x: x[UDP].sport == self.rport) if asConvo: return Conversation(m) else: return m def fromEither(self, asConvo=True): ''' Works as fromLocal, but includes packets originating either local or remotely. ''' m = self.pktlist.filter( lambda x: x[UDP].sport == self.lport or x[UDP].sport == self.rport) if asConvo: return Conversation(m) else: return m def subrange(self, end, start=0, asConvo=True): ''' Select a range of packets by position index. ''' m = self.pktlist[start:end] if asConvo: return Conversation(m) else: return m def size(self): ''' Returns the size (in bytes) of each UDP payload in the Conversation as a numpy array. ''' plens = np.array([len(c[Raw].load) for c in self.pktlist]) return plens def sizes(self): ''' Returns the set of sizes (in bytes) of packet payloads. ''' return set(self.size()) def sizeIs(self, size, asConvo=True): ''' Returns a filtered PacketList object containing only those packets with payloads of the specified size. ''' m = self.pktlist.filter(lambda x: len(x[Raw].load) == size) if asConvo: return Conversation(m) else: return m def sizeBelow(self, size, asConvo=True): ''' Returns a filtered PacketList object containing only those packets with payloads smaller than or equal to size ''' m = self.pktlist.filter(lambda x: len(x[Raw].load) <= size) if asConvo: return Conversation(m) else: return m def sizeAbove(self, size, asConvo=True): ''' Returns a filtered PacketList object containing only those packets with payloads larger than or equal to the specified number of bytes. ''' m = self.pktlist.filter(lambda x: len(x[Raw].load) >= size) if asConvo: return Conversation(m) else: return m def sizeHistogram(self, plot=True): ''' Simplifies the procss of displaying histograms of payload sizes. This is a useful way to classify packets. If plot = True, it will display the histogram, else it will return the tuple ( counts, bins ). If you want finer grained control just import pylab as pl and get cracking! ''' if plot: pl.hist(self.size()) pl.show() else: return pl.histogram(self.size()) def statePlot(self, bucketwidth, offsets, filename='state.dot', display=True): ''' bucketwidth is the number of bytes in each section of the packet. Offset selects which section is of interest. The result of this function is a graph where the nodes are packet states and the directed arcs show numbered transitions between states. Beware, if there are a large number of states and indices the graph will likely be indecipherable if it even generates. Choose the values wisely. In future this will be more useful, based on multiple lengths using a scapy dissection definition. For now a spec for byte samples and offsets is all you get. Tools will be included to look at bit patterns in order to determine the existence and properties of individual flags. However, at this stage, that should be both trivial and irrelevant.''' statesamples = Samples(self, bucketwidth * (np.array(offsets).max() + 1), bucketwidth) valuesetlist = [] valueslist = [] for o in offsets: valueset = statesamples.asHexSet(o) print valueset valuesetlist.append(valueset) valueslist.append(statesamples.asHex(o)) nodelist = [n for n in it.product(*valuesetlist)] G = nx.MultiDiGraph() G.add_nodes_from(nodelist) for i in range(len(valueslist[0]) - 1): nodetuple = [] for j in range(len(offsets)): nodetuple.append(valueslist[j][i]) thisnodetuple = tuple(nodetuple) nodetuple = [] for j in range(len(offsets)): nodetuple.append(valueslist[j][i + 1]) nextnodetuple = tuple(nodetuple) # before adding edge, color according to local or remote origin if self.pktlist[i][UDP].sport == self.lport: edgecolour = 'green' if self.pktlist[i][UDP].sport == self.rport: edgecolour = 'blue' G.add_edge(thisnodetuple, nextnodetuple, label=i, color=edgecolour) # clean out unused states from graph for n in G.nodes(): if G.neighbors(n) == []: G.remove_node(n) GA = nx.to_agraph(G) GA.edge_attr['penwidth'] = 3.0 GA.layout() GA.write(filename) if display: Popen(['xdot', filename]) return
class debug: recv = PacketList([], "Received") sent = PacketList([], "Sent") match = SndRcvList([], "Matched") crashed_on = None # type: Optional[Tuple[Type[Packet], bytes]]
class Automaton: states = {} # type: Dict[str, _StateWrapper] state = None # type: ATMT.NewStateRequested recv_conditions = {} # type: Dict[str, List[_StateWrapper]] conditions = {} # type: Dict[str, List[_StateWrapper]] ioevents = {} # type: Dict[str, List[_StateWrapper]] timeout = { } # type: Dict[str, List[Tuple[int, _StateWrapper]]] # noqa: E501 actions = {} # type: Dict[str, List[_StateWrapper]] initial_states = [] # type: List[_StateWrapper] stop_states = [] # type: List[_StateWrapper] ionames = [] # type: List[str] iosupersockets = [] # type: List[SuperSocket] # Internals def __init__(self, *args, **kargs): # type: (Any, Any) -> None external_fd = kargs.pop("external_fd", {}) self.send_sock_class = kargs.pop("ll", conf.L3socket) self.recv_sock_class = kargs.pop("recvsock", conf.L2listen) self.is_atmt_socket = kargs.pop("is_atmt_socket", False) self.started = threading.Lock() self.threadid = None # type: Optional[int] self.breakpointed = None self.breakpoints = set() # type: Set[_StateWrapper] self.interception_points = set() # type: Set[_StateWrapper] self.intercepted_packet = None # type: Union[None, Packet] self.debug_level = 0 self.init_args = args self.init_kargs = kargs self.io = type.__new__(type, "IOnamespace", (), {}) self.oi = type.__new__(type, "IOnamespace", (), {}) self.cmdin = ObjectPipe[Message]("cmdin") self.cmdout = ObjectPipe[Message]("cmdout") self.ioin = {} self.ioout = {} self.packets = PacketList() # type: PacketList for n in self.__class__.ionames: extfd = external_fd.get(n) if not isinstance(extfd, tuple): extfd = (extfd, extfd) ioin, ioout = extfd if ioin is None: ioin = ObjectPipe("ioin") else: ioin = self._IO_fdwrapper(ioin, None) if ioout is None: ioout = ObjectPipe("ioout") else: ioout = self._IO_fdwrapper(None, ioout) self.ioin[n] = ioin self.ioout[n] = ioout ioin.ioname = n ioout.ioname = n setattr(self.io, n, self._IO_mixer(ioout, ioin)) setattr(self.oi, n, self._IO_mixer(ioin, ioout)) for stname in self.states: setattr(self, stname, _instance_state(getattr(self, stname))) self.start() def parse_args(self, debug=0, store=1, **kargs): # type: (int, int, Any) -> None self.debug_level = debug if debug: conf.logLevel = logging.DEBUG self.socket_kargs = kargs self.store_packets = store def master_filter(self, pkt): # type: (Packet) -> bool return True def my_send(self, pkt): # type: (Packet) -> None self.send_sock.send(pkt) # Utility classes and exceptions class _IO_fdwrapper: def __init__( self, rd, # type: Union[int, ObjectPipe[bytes], None] wr # type: Union[int, ObjectPipe[bytes], None] ): # type: (...) -> None if rd is not None and not isinstance(rd, (int, ObjectPipe)): rd = rd.fileno() # type: ignore if wr is not None and not isinstance(wr, (int, ObjectPipe)): wr = wr.fileno() # type: ignore self.rd = rd self.wr = wr def fileno(self): # type: () -> int if isinstance(self.rd, ObjectPipe): return self.rd.fileno() elif isinstance(self.rd, int): return self.rd return 0 def read(self, n=65535): # type: (int) -> Optional[bytes] if isinstance(self.rd, ObjectPipe): return self.rd.recv(n) elif isinstance(self.rd, int): return os.read(self.rd, n) return None def write(self, msg): # type: (bytes) -> int if isinstance(self.wr, ObjectPipe): return self.wr.send(msg) elif isinstance(self.wr, int): return os.write(self.wr, msg) return 0 def recv(self, n=65535): # type: (int) -> Optional[bytes] return self.read(n) def send(self, msg): # type: (bytes) -> int return self.write(msg) class _IO_mixer: def __init__( self, rd, # type: ObjectPipe[Any] wr, # type: ObjectPipe[Any] ): # type: (...) -> None self.rd = rd self.wr = wr def fileno(self): # type: () -> Any if isinstance(self.rd, ObjectPipe): return self.rd.fileno() return self.rd def recv(self, n=None): # type: (Optional[int]) -> Any return self.rd.recv(n) def read(self, n=None): # type: (Optional[int]) -> Any return self.recv(n) def send(self, msg): # type: (str) -> int return self.wr.send(msg) def write(self, msg): # type: (str) -> int return self.send(msg) class AutomatonException(Exception): def __init__(self, msg, state=None, result=None): # type: (str, Optional[Message], Optional[str]) -> None Exception.__init__(self, msg) self.state = state self.result = result class AutomatonError(AutomatonException): pass class ErrorState(AutomatonException): pass class Stuck(AutomatonException): pass class AutomatonStopped(AutomatonException): pass class Breakpoint(AutomatonStopped): pass class Singlestep(AutomatonStopped): pass class InterceptionPoint(AutomatonStopped): def __init__(self, msg, state=None, result=None, packet=None): # type: (str, Optional[Message], Optional[str], Optional[str]) -> None # noqa: E501 Automaton.AutomatonStopped.__init__(self, msg, state=state, result=result) # noqa: E501 self.packet = packet class CommandMessage(AutomatonException): pass # Services def debug(self, lvl, msg): # type: (int, str) -> None if self.debug_level >= lvl: log_runtime.debug(msg) def send(self, pkt): # type: (Packet) -> None if self.state.state in self.interception_points: self.debug(3, "INTERCEPT: packet intercepted: %s" % pkt.summary()) self.intercepted_packet = pkt self.cmdout.send( Message(type=_ATMT_Command.INTERCEPT, state=self.state, pkt=pkt)) cmd = self.cmdin.recv() if not cmd: self.debug(3, "CANCELLED") return self.intercepted_packet = None if cmd.type == _ATMT_Command.REJECT: self.debug(3, "INTERCEPT: packet rejected") return elif cmd.type == _ATMT_Command.REPLACE: pkt = cmd.pkt self.debug(3, "INTERCEPT: packet replaced by: %s" % pkt.summary()) # noqa: E501 elif cmd.type == _ATMT_Command.ACCEPT: self.debug(3, "INTERCEPT: packet accepted") else: raise self.AutomatonError("INTERCEPT: unknown verdict: %r" % cmd.type) # noqa: E501 self.my_send(pkt) self.debug(3, "SENT : %s" % pkt.summary()) if self.store_packets: self.packets.append(pkt.copy()) def __iter__(self): # type: () -> Automaton return self def __del__(self): # type: () -> None self.stop() def _run_condition(self, cond, *args, **kargs): # type: (_StateWrapper, Any, Any) -> None try: self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname)) # noqa: E501 cond(self, *args, **kargs) except ATMT.NewStateRequested as state_req: self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state)) # noqa: E501 if cond.atmt_type == ATMT.RECV: if self.store_packets: self.packets.append(args[0]) for action in self.actions[cond.atmt_condname]: self.debug(2, " + Running action [%s]" % action.__name__) action(self, *state_req.action_args, **state_req.action_kargs) raise except Exception as e: self.debug(2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e)) # noqa: E501 raise else: self.debug(2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname)) # noqa: E501 def _do_start(self, *args, **kargs): # type: (Any, Any) -> None ready = threading.Event() _t = threading.Thread(target=self._do_control, args=(ready, ) + (args), kwargs=kargs, name="scapy.automaton _do_start") _t.daemon = True _t.start() ready.wait() def _do_control(self, ready, *args, **kargs): # type: (threading.Event, Any, Any) -> None with self.started: self.threadid = threading.current_thread().ident if self.threadid is None: self.threadid = 0 # Update default parameters a = args + self.init_args[len(args):] k = self.init_kargs.copy() k.update(kargs) self.parse_args(*a, **k) # Start the automaton self.state = self.initial_states[0](self) self.send_sock = self.send_sock_class(**self.socket_kargs) self.listen_sock = self.recv_sock_class(**self.socket_kargs) self.packets = PacketList(name="session[%s]" % self.__class__.__name__) # noqa: E501 singlestep = True iterator = self._do_iter() self.debug(3, "Starting control thread [tid=%i]" % self.threadid) # Sync threads ready.set() try: while True: c = self.cmdin.recv() if c is None: return None self.debug(5, "Received command %s" % c.type) if c.type == _ATMT_Command.RUN: singlestep = False elif c.type == _ATMT_Command.NEXT: singlestep = True elif c.type == _ATMT_Command.FREEZE: continue elif c.type == _ATMT_Command.STOP: if self.stop_states: # There is a stop state self.state = self.stop_states[0](self) iterator = self._do_iter() else: # Act as FORCESTOP break elif c.type == _ATMT_Command.FORCESTOP: break while True: state = next(iterator) if isinstance(state, self.CommandMessage): break elif isinstance(state, self.Breakpoint): c = Message(type=_ATMT_Command.BREAKPOINT, state=state) # noqa: E501 self.cmdout.send(c) break if singlestep: c = Message(type=_ATMT_Command.SINGLESTEP, state=state) # noqa: E501 self.cmdout.send(c) break except (StopIteration, RuntimeError): c = Message(type=_ATMT_Command.END, result=self.final_state_output) self.cmdout.send(c) except Exception as e: exc_info = sys.exc_info() self.debug( 3, "Transferring exception from tid=%i:\n%s" % (self.threadid, traceback.format_exception(*exc_info))) # noqa: E501 m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info) # noqa: E501 self.cmdout.send(m) self.debug(3, "Stopping control thread (tid=%i)" % self.threadid) self.threadid = None def _do_iter(self): # type: () -> Iterator[Union[Automaton.AutomatonException, Automaton.AutomatonStopped, ATMT.NewStateRequested, None]] # noqa: E501 while True: try: self.debug(1, "## state=[%s]" % self.state.state) # Entering a new state. First, call new state function if self.state.state in self.breakpoints and self.state.state != self.breakpointed: # noqa: E501 self.breakpointed = self.state.state yield self.Breakpoint( "breakpoint triggered on state %s" % self.state.state, # noqa: E501 state=self.state.state) self.breakpointed = None state_output = self.state.run() if self.state.error: raise self.ErrorState( "Reached %s: [%r]" % (self.state.state, state_output), # noqa: E501 result=state_output, state=self.state.state) # noqa: E501 if self.state.final: self.final_state_output = state_output return if state_output is None: state_output = () elif not isinstance(state_output, list): state_output = state_output, # If there are commandMessage, we should skip immediate # conditions. if not select_objects([self.cmdin], 0): # Then check immediate conditions for cond in self.conditions[self.state.state]: self._run_condition(cond, *state_output) # If still there and no conditions left, we are stuck! if (len(self.recv_conditions[self.state.state]) == 0 and len(self.ioevents[self.state.state]) == 0 and len(self.timeout[self.state.state]) == 1): raise self.Stuck("stuck in [%s]" % self.state.state, state=self.state.state, result=state_output) # Finally listen and pay attention to timeouts expirations = iter(self.timeout[self.state.state]) next_timeout, timeout_func = next(expirations) t0 = time.time() fds = [self.cmdin] if len(self.recv_conditions[self.state.state]) > 0: fds.append(self.listen_sock) for ioev in self.ioevents[self.state.state]: fds.append(self.ioin[ioev.atmt_ioname]) while True: t = time.time() - t0 if next_timeout is not None: if next_timeout <= t: self._run_condition(timeout_func, *state_output) next_timeout, timeout_func = next(expirations) if next_timeout is None: remain = 0 else: remain = next_timeout - t self.debug(5, "Select on %r" % fds) r = select_objects(fds, remain) self.debug(5, "Selected %r" % r) for fd in r: self.debug(5, "Looking at %r" % fd) if fd == self.cmdin: yield self.CommandMessage( "Received command message") # noqa: E501 elif fd == self.listen_sock: pkt = self.listen_sock.recv(MTU) if pkt is not None: if self.master_filter(pkt): self.debug(3, "RECVD: %s" % pkt.summary()) # noqa: E501 for rcvcond in self.recv_conditions[ self.state.state]: # noqa: E501 self._run_condition( rcvcond, pkt, *state_output) # noqa: E501 else: self.debug(4, "FILTR: %s" % pkt.summary()) # noqa: E501 else: self.debug(3, "IOEVENT on %s" % fd.ioname) for ioevt in self.ioevents[self.state.state]: if ioevt.atmt_ioname == fd.ioname: self._run_condition( ioevt, fd, *state_output) # noqa: E501 except ATMT.NewStateRequested as state_req: self.debug(2, "switching from [%s] to [%s]" % (self.state.state, state_req.state)) # noqa: E501 self.state = state_req yield state_req def __repr__(self): # type: () -> str return "<Automaton %s [%s]>" % (self.__class__.__name__, [ "HALTED", "RUNNING" ][self.started.locked()]) # Public API def add_interception_points(self, *ipts): # type: (Any) -> None for ipt in ipts: if hasattr(ipt, "atmt_state"): ipt = ipt.atmt_state self.interception_points.add(ipt) def remove_interception_points(self, *ipts): # type: (Any) -> None for ipt in ipts: if hasattr(ipt, "atmt_state"): ipt = ipt.atmt_state self.interception_points.discard(ipt) def add_breakpoints(self, *bps): # type: (Any) -> None for bp in bps: if hasattr(bp, "atmt_state"): bp = bp.atmt_state self.breakpoints.add(bp) def remove_breakpoints(self, *bps): # type: (Any) -> None for bp in bps: if hasattr(bp, "atmt_state"): bp = bp.atmt_state self.breakpoints.discard(bp) def start(self, *args, **kargs): # type: (Any, Any) -> None if not self.started.locked(): self._do_start(*args, **kargs) def run( self, resume=None, # type: Optional[Message] wait=True # type: Optional[bool] ): # type: (...) -> Any if resume is None: resume = Message(type=_ATMT_Command.RUN) self.cmdin.send(resume) if wait: try: c = self.cmdout.recv() if c is None: return None except KeyboardInterrupt: self.cmdin.send(Message(type=_ATMT_Command.FREEZE)) return None if c.type == _ATMT_Command.END: return c.result elif c.type == _ATMT_Command.INTERCEPT: raise self.InterceptionPoint("packet intercepted", state=c.state.state, packet=c.pkt) # noqa: E501 elif c.type == _ATMT_Command.SINGLESTEP: raise self.Singlestep("singlestep state=[%s]" % c.state.state, state=c.state.state) # noqa: E501 elif c.type == _ATMT_Command.BREAKPOINT: raise self.Breakpoint("breakpoint triggered on state [%s]" % c.state.state, state=c.state.state) # noqa: E501 elif c.type == _ATMT_Command.EXCEPTION: six.reraise(c.exc_info[0], c.exc_info[1], c.exc_info[2]) return None def runbg(self, resume=None, wait=False): # type: (Optional[Message], Optional[bool]) -> None self.run(resume, wait) def next(self): # type: () -> Any return self.run(resume=Message(type=_ATMT_Command.NEXT)) __next__ = next def _flush_inout(self): # type: () -> None with self.started: # Flush command pipes while True: r = select_objects([self.cmdin, self.cmdout], 0) if not r: break for fd in r: fd.recv() def stop(self): # type: () -> None self.cmdin.send(Message(type=_ATMT_Command.STOP)) self._flush_inout() def forcestop(self): # type: () -> None self.cmdin.send(Message(type=_ATMT_Command.FORCESTOP)) self._flush_inout() def restart(self, *args, **kargs): # type: (Any, Any) -> None self.stop() self.start(*args, **kargs) def accept_packet( self, pkt=None, # type: Optional[Packet] wait=False # type: Optional[bool] ): # type: (...) -> Any rsm = Message() if pkt is None: rsm.type = _ATMT_Command.ACCEPT else: rsm.type = _ATMT_Command.REPLACE rsm.pkt = pkt return self.run(resume=rsm, wait=wait) def reject_packet( self, wait=False # type: Optional[bool] ): # type: (...) -> Any rsm = Message(type=_ATMT_Command.REJECT) return self.run(resume=rsm, wait=wait)
class Ecu(object): """A ECU object can be used to - track the states of an ECU. - to log all modification to an ECU - to extract supported responses of a real ECU Usage: >>> print("This ecu logs, tracks and creates supported responses") >>> my_virtual_ecu = Ecu() >>> my_virtual_ecu.update(PacketList([...])) >>> my_virtual_ecu.supported_responses >>> print("Another ecu just tracks") >>> my_tracking_ecu = Ecu(logging=False, store_supported_responses=False) # noqa: E501 >>> my_tracking_ecu.update(PacketList([...])) >>> print("Another ecu just logs all modifications to it") >>> my_logging_ecu = Ecu(verbose=False, store_supported_responses=False) # noqa: E501 >>> my_logging_ecu.update(PacketList([...])) >>> my_logging_ecu.log >>> print("Another ecu just creates supported responses") >>> my_response_ecu = Ecu(verbose=False, logging=False) >>> my_response_ecu.update(PacketList([...])) >>> my_response_ecu.supported_responses """ def __init__(self, init_session=None, init_security_level=None, init_communication_control=None, logging=True, verbose=True, store_supported_responses=True): """ Initialize an Ecu object :param init_session: An initial session :param init_security_level: An initial security level :param init_communication_control: An initial communication control setting :param logging: Turn logging on or off. Default is on. :param verbose: Turn tracking on or off. Default is on. :param store_supported_responses: Turn creation of supported responses on or off. Default is on. """ self.state = EcuState(session=init_session or 1, security_level=init_security_level or 0, communication_control=init_communication_control or 0) self.verbose = verbose self.logging = logging self.store_supported_responses = store_supported_responses self.log = defaultdict(list) self._supported_responses = list() self._unanswered_packets = PacketList() @property def current_session(self): return self.state.session @current_session.setter def current_session(self, ses): self.state.session = ses @property def current_security_level(self): return self.state.security_level @current_security_level.setter def current_security_level(self, sec): self.state.security_level = sec @property def communication_control(self): return self.state.communication_control @communication_control.setter def communication_control(self, cc): self.state.communication_control = cc def reset(self): self.state.reset() self.state.session = 1 self.state.security_level = 0 self.state.communication_control = 0 def update(self, p): if isinstance(p, PacketList): for pkt in p: self._update(pkt) elif not isinstance(p, Packet): raise Scapy_Exception("Provide a Packet object for an update") else: self._update(p) def _update(self, pkt): if self.verbose: print(repr(self), repr(pkt)) if self.store_supported_responses: self._update_supported_responses(pkt) if self.logging: self._update_log(pkt) self._update_internal_state(pkt) def _update_log(self, pkt): for layer in pkt.layers(): if hasattr(layer, "get_log"): log_key, log_value = layer.get_log(pkt) self.log[log_key].append((pkt.time, log_value)) def _update_internal_state(self, pkt): for layer in pkt.layers(): if hasattr(layer, "modifies_ecu_state"): layer.modifies_ecu_state(pkt, self) def _update_supported_responses(self, pkt): self._unanswered_packets += PacketList([pkt]) answered, unanswered = self._unanswered_packets.sr() for _, resp in answered: ecu_resp = EcuResponse(session=self.current_session, security_level=self.current_security_level, responses=resp) if ecu_resp not in self._supported_responses: if self.verbose: print("[+] ", repr(ecu_resp)) self._supported_responses.append(ecu_resp) else: if self.verbose: print("[-] ", repr(ecu_resp)) self._unanswered_packets = unanswered @property def supported_responses(self): # This sorts responses in the following order: # 1. Positive responses first # 2. Lower ServiceID first # 3. Longer (more specific) responses first self._supported_responses.sort( key=lambda x: (x.responses[0].service == 0x7f, x.responses[0]. service, 0xffffffff - len(x.responses[0]))) return self._supported_responses @property def unanswered_packets(self): return self._unanswered_packets def __repr__(self): return "ses: %03d sec: %03d cc: %d" % (self.current_session, self.current_security_level, self.communication_control)
def _do_control(self, ready, *args, **kargs): # type: (threading.Event, Any, Any) -> None with self.started: self.threadid = threading.current_thread().ident if self.threadid is None: self.threadid = 0 # Update default parameters a = args + self.init_args[len(args):] k = self.init_kargs.copy() k.update(kargs) self.parse_args(*a, **k) # Start the automaton self.state = self.initial_states[0](self) self.send_sock = self.send_sock_class(**self.socket_kargs) self.listen_sock = self.recv_sock_class(**self.socket_kargs) self.packets = PacketList(name="session[%s]" % self.__class__.__name__) # noqa: E501 singlestep = True iterator = self._do_iter() self.debug(3, "Starting control thread [tid=%i]" % self.threadid) # Sync threads ready.set() try: while True: c = self.cmdin.recv() if c is None: return None self.debug(5, "Received command %s" % c.type) if c.type == _ATMT_Command.RUN: singlestep = False elif c.type == _ATMT_Command.NEXT: singlestep = True elif c.type == _ATMT_Command.FREEZE: continue elif c.type == _ATMT_Command.STOP: if self.stop_states: # There is a stop state self.state = self.stop_states[0](self) iterator = self._do_iter() else: # Act as FORCESTOP break elif c.type == _ATMT_Command.FORCESTOP: break while True: state = next(iterator) if isinstance(state, self.CommandMessage): break elif isinstance(state, self.Breakpoint): c = Message(type=_ATMT_Command.BREAKPOINT, state=state) # noqa: E501 self.cmdout.send(c) break if singlestep: c = Message(type=_ATMT_Command.SINGLESTEP, state=state) # noqa: E501 self.cmdout.send(c) break except (StopIteration, RuntimeError): c = Message(type=_ATMT_Command.END, result=self.final_state_output) self.cmdout.send(c) except Exception as e: exc_info = sys.exc_info() self.debug( 3, "Transferring exception from tid=%i:\n%s" % (self.threadid, traceback.format_exception(*exc_info))) # noqa: E501 m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info) # noqa: E501 self.cmdout.send(m) self.debug(3, "Stopping control thread (tid=%i)" % self.threadid) self.threadid = None
def _do_control(self, ready, *args, **kargs): with self.started: self.threadid = threading.currentThread().ident # Update default parameters a = args + self.init_args[len(args):] k = self.init_kargs.copy() k.update(kargs) self.parse_args(*a, **k) # Start the automaton self.state = self.initial_states[0](self) self.send_sock = self.send_sock_class() self.listen_sock = self.recv_sock_class(**self.socket_kargs) self.packets = PacketList(name="session[%s]" % self.__class__.__name__) singlestep = True iterator = self._do_iter() self.debug(3, "Starting control thread [tid=%i]" % self.threadid) # Sync threads ready.set() try: while True: c = self.cmdin.recv() self.debug(5, "Received command %s" % c.type) if c.type == _ATMT_Command.RUN: singlestep = False elif c.type == _ATMT_Command.NEXT: singlestep = True elif c.type == _ATMT_Command.FREEZE: continue elif c.type == _ATMT_Command.STOP: break while True: state = next(iterator) if isinstance(state, self.CommandMessage): break elif isinstance(state, self.Breakpoint): c = Message(type=_ATMT_Command.BREAKPOINT, state=state) self.cmdout.send(c) break if singlestep: c = Message(type=_ATMT_Command.SINGLESTEP, state=state) self.cmdout.send(c) break except StopIteration as e: c = Message(type=_ATMT_Command.END, result=e.args[0]) self.cmdout.send(c) except Exception as e: exc_info = sys.exc_info() self.debug( 3, "Transfering exception from tid=%i:\n%s" % (self.threadid, traceback.format_exc(exc_info))) m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info) self.cmdout.send(m) self.debug(3, "Stopping control thread (tid=%i)" % self.threadid) self.threadid = None
def defrag(plist): """defrag(plist) -> ([not fragmented], [defragmented], [ [bad fragments], [bad fragments], ... ])""" frags = {} nofrag = PacketList() for p in plist: ip = p[IP] if IP not in p: nofrag.append(p) continue if ip.frag == 0 and ip.flags & 1 == 0: nofrag.append(p) continue uniq = (ip.id,ip.src,ip.dst,ip.proto) if uniq in frags: frags[uniq].append(p) else: frags[uniq] = PacketList([p]) defrag = [] missfrag = [] for lst in frags.itervalues(): lst.sort(lambda x,y:cmp(x.frag, y.frag)) p = lst[0] if p.frag > 0: missfrag.append(lst) continue p = p.copy() if Padding in p: del(p[Padding].underlayer.payload) ip = p[IP] if ip.len is None or ip.ihl is None: clen = len(ip.payload) else: clen = ip.len - (ip.ihl<<2) txt = Raw() for q in lst[1:]: if clen != q.frag<<3: if clen > q.frag<<3: warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q)) missfrag.append(lst) txt = None break if q[IP].len is None or q[IP].ihl is None: clen += len(q[IP].payload) else: clen += q[IP].len - (q[IP].ihl<<2) if Padding in q: del(q[Padding].underlayer.payload) txt.add_payload(q[IP].payload.copy()) if txt is None: continue ip.flags &= ~1 # !MF del(ip.chksum) del(ip.len) p = p/txt defrag.append(p) defrag2=PacketList() for p in defrag: defrag2.append(p.__class__(str(p))) return nofrag,defrag2,missfrag