| |
| import time |
| from scapy.sendrecv import AsyncSniffer |
| from scapy.all import IP, TCP, UDP, DNS |
|
|
| def process_packet(pkt): |
| """Processes a Scapy packet into a simple dictionary.""" |
| d = {"timestamp": pkt.time} |
| if pkt.haslayer(IP): |
| ip = pkt[IP] |
| d.update(src=ip.src, dst=ip.dst, ttl=ip.ttl, length=len(pkt)) |
| if pkt.haslayer(TCP): |
| t = pkt[TCP] |
| d.update( |
| proto=6, src_port=t.sport, dst_port=t.dport, flags=str(t.flags), |
| info=f"TCP {ip.src}:{t.sport} → {ip.dst}:{t.dport}" |
| ) |
| elif pkt.haslayer(UDP): |
| u = pkt[UDP] |
| d.update(proto=17, src_port=u.sport, dst_port=u.dport, flags="-") |
| if pkt.haslayer(DNS) and hasattr(pkt[DNS], 'qd') and pkt[DNS].qd is not None: |
| qname = pkt[DNS].qd.qname |
| |
| qname_str = qname.decode(errors='ignore') if isinstance(qname, bytes) else str(qname) |
| d.update(proto="DNS", info=f"DNS Query for {qname_str}") |
| else: |
| d.update(info=f"UDP {ip.src}:{u.sport} → {ip.dst}:{u.dport}") |
| else: |
| d.setdefault("proto", ip.proto) |
| else: |
| d.update(src="N/A", dst="N/A", proto="Other", length=len(pkt)) |
| return d |
|
|
| def start_packet_capture(app, socketio, interface=None, filter_expr="ip"): |
| """ |
| Sniffs packets in a background thread, adds them to the app's deque, |
| and emits every packet to connected clients. |
| """ |
| def _handle(pkt): |
| try: |
| data = process_packet(pkt) |
| except Exception: |
| return |
|
|
| |
| app.captured_packets.append(data) |
|
|
| |
| socketio.emit("new_packet", data) |
|
|
| sniffer = AsyncSniffer( |
| iface=interface, |
| filter=filter_expr, |
| prn=_handle, |
| store=False |
| ) |
| sniffer.start() |