Raw packet captures are not features; they are bytes on a wire. A network flow, one conversation between two endpoints, is usually summarised into a fixed-length numeric vector before any model sees it.
| Feature | What it captures |
|---|---|
| Flow duration | Very short flows often indicate scanning; very long ones can indicate exfiltration or a maintained backdoor |
| Packets per second | A sudden spike relative to a host's baseline often indicates a flood or scan |
| Mean and variance of packet size | Automated tools tend to send suspiciously uniform packet sizes compared to human-driven traffic |
| Ratio of bytes sent to received | A ratio far from what a given protocol normally produces can indicate exfiltration or beaconing |
| TCP flag counts (SYN, RST, FIN) | An unusual ratio of SYNs to completed handshakes is a classic scan signature |
These are the same style of feature used to build the NSL-KDD and CICIDS benchmark datasets this course cites in Unit 6.
flow_features.py
import numpy as np
def flow_features(packets: list[dict]) -> dict:
"""packets: list of {'ts': float, 'size': int, 'direction': 'out'|'in',
'flags': set[str]} for one 5-tuple flow."""
sizes = np.array([p["size"] for p in packets])
timestamps = np.array([p["ts"] for p in packets])
out_bytes = sum(p["size"] for p in packets if p["direction"] == "out")
in_bytes = sum(p["size"] for p in packets if p["direction"] == "in")
return {
"duration": timestamps.max() - timestamps.min(),
"packets_per_second": len(packets) / max(timestamps.max() - timestamps.min(), 1e-3),
"mean_packet_size": sizes.mean(),
"size_variance": sizes.var(),
"bytes_out_in_ratio": out_bytes / max(in_bytes, 1),
"syn_count": sum(1 for p in packets if "SYN" in p["flags"]),
"rst_count": sum(1 for p in packets if "RST" in p["flags"]),
}
Try it yourself: Spot the Scan
Two flows are summarised with flow_features. Flow A: duration 0.4 seconds, 38 SYN flags, 0 completed connections. Flow B: duration 340 seconds, mean packet size 1480 bytes with near-zero variance, bytes_out_in_ratio of 48. Which flow more likely represents a port scan, and which more likely represents automated data exfiltration? Name the specific field in each that gives it away.

