Mirai and IoT Botnets: Blocking Their Patterns with XDP
The Mirai botnet XDP story began in 2016 when the original Mirai malware turned hundreds of thousands of IoT devices into an attack swarm, yet in 2026 its evolved descendants still power some of the largest volumetric floods on the Internet. Kernel-level XDP filtering offers the earliest possible interception point—processing packets before the kernel network stack allocates socket buffers—making it the most resource-efficient defense against pattern-based amplification and SYN floods that Mirai variants continue to deploy at scale.
This article examines which Mirai traffic signatures remain dominant in 2026, how XDP programs parse and drop them in sub-microsecond time, and how complementary nftables stateful rules close gaps that a stateless XDP layer cannot address alone. Whether you operate game servers, API gateways, or edge compute nodes, understanding Mirai's mutation cycle and the kernel hooks that can halt it will reduce your attack surface without burning CPU on userspace inspection.
Why Mirai Patterns Still Matter in 2026
Mirai's initial C code leak spawned a Cambrian explosion of forks—Satori, Okiru, Masuta, SORA, Moobot—each adding new exploits but preserving the core attack primitives: UDP floods to arbitrary ports, TCP SYN floods with minimal options, and GRE tunneling for reflection. Security vendors anticipated that patched firmware and IPv6 adoption would starve the botnet of targets, yet three dynamics kept Mirai alive:
- Supply-chain delays: even firmware updates published in 2023 take eighteen months to propagate to consumer routers, IP cameras, and DVRs in emerging markets.
- IPv4 address recycling: cloud providers churn elastic IPs every few hours, which means previously cleaned addresses are reassigned to new customers who inherit residual botnet membership unless they explicitly reset TCP sequence numbers and firewall state.
- Rental marketplaces: Telegram channels and dark-web stresser panels commoditized Mirai-as-a-Service, lowering the skill floor to launch 100+ Gbps attacks for under fifty dollars per hour.
Consequently, PAKKT.io telemetry shows that Mirai-family signatures account for roughly 40 percent of all floods targeting UDP port ranges 27000–27100 (Source Engine query) and TCP port 25565 (Minecraft Java Edition). The attack fingerprint is distinctive enough that a handful of BPF map entries can reject the majority of malicious packets before they consume conntrack table slots or trigger expensive deep-packet inspection.
Signature Clusters Observed in 2026
Modern Mirai variants blend multiple attack vectors in the same campaign, rotating every few minutes to evade static rate-limits. The five most common patterns detected by XDP telemetry are:
1. UDP Flood with Fixed Payload Length
Classic Mirai sends 512-byte, 768-byte, or 1024-byte UDP datagrams to a single destination port at line rate. The payload is either random bytes or a repeated ASCII string. XDP can filter by:
if (udp_header->dest == htons(TARGET_PORT) &&
(data_end - data) >= MIN_PKT_LEN &&
(data_end - data) <= MAX_PKT_LEN) {
return XDP_DROP;
}
PAKKT rules expose min_packet_size and max_packet_size fields, so operators set a narrow window (for example, 512–1024 bytes) on game-query ports while allowing smaller keep-alive packets and larger legitimate payloads on other services.
2. SYN Flood with No TCP Options
Mirai's SYN packets typically omit MSS, window-scale, and timestamp options to minimize per-packet CPU work on the bot. A stateless XDP program can count TCP header length:
struct tcphdr *tcp = (void *)(ip + 1);
if ((tcp->doff * 4) == 20 && (tcp->syn && !tcp->ack)) {
// Bare 20-byte header, likely bot
return XDP_DROP;
}
Because legitimate clients almost always negotiate at least MSS and SACK, blocking zero-option SYNs cuts attack volume by 60–80 percent with negligible false positives on modern stacks.
3. DNS Amplification via Spoofed Source
Compromised resolvers reflect large DNSSEC responses toward the victim's IP. XDP on the victim's edge interface sees inbound UDP/53 packets that never correlate with an outbound query. A combined approach works best:
- XDP: enforce a global PPS ceiling on UDP/53 inbound (e.g., 10,000 pps) using a BPF map rate-limit.
- nftables: track conntrack state and drop UDP/53 packets in state
INVALIDor without a matching outbound flow in the past 2 seconds.
nft add rule inet pakkt input udp sport 53 ct state invalid drop
nft add rule inet pakkt input udp sport 53 meter dns_rate { ip saddr timeout 2s limit rate over 100/second } drop
4. GRE Reflection
Misconfigured WAN optimizers and VPN gateways reflect GRE (protocol 47) packets. Mirai scans for open GRE endpoints and spoofs the victim's IP as the inner header destination. XDP drops unsolicited GRE:
if (ip->protocol == IPPROTO_GRE) {
return XDP_DROP; // unless you run a legitimate GRE tunnel
}
PAKKT users can create a rule with protocol = GRE and rule_type = block in the web dashboard; the engine compiles it into the BPF map within seconds.
5. ICMP Echo Request Floods
Less common but still present: Mirai sends waves of 64-byte or 84-byte ICMP echo requests. XDP programs parse the ICMP type field and apply per-protocol rate-limits. For example, allow 100 pps of ICMP type 8 (echo request) and drop the rest:
if (icmp->type == 8) {
// Check per-source or global ICMP rate-limit in BPF map
}
On a dual-layer stack, nftables can further throttle per source with a meter, while XDP enforces the aggregate ceiling.
How XDP Processes Mirai Packets in the PAKKT Engine
The PAKKT Engine is a single XDP program attached to each monitored interface, capable of evaluating up to 256 simultaneous rules stored in a BPF hash map. When a packet arrives at the NIC driver's ring buffer:
- Driver RX: the NIC writes the frame into a memory page and triggers an XDP hook before
sk_buffallocation. - Ethernet parse: the program reads the EtherType; non-IPv4/IPv6 frames can be passed or dropped by policy.
- IP parse: extract source/destination IP, protocol number, and total length. Check IP blacklist/whitelist map (O(1) hash lookup).
- L4 parse: if TCP or UDP, read source and destination port. If ICMP, read type and code.
- Rule iteration: for each active rule in the map, test whether the packet matches port range, protocol, and size constraints. Stop at the first match.
- Action dispatch:
block→ returnXDP_DROP.rate_limit→ increment a per-rule packet counter with a time-window; if exceeded, returnXDP_DROP; otherwiseXDP_PASS.allow_only→ if matched, returnXDP_PASS; all other packets are dropped by a default-deny rule at the end of the chain.
- Fallback: if no rule matches, return
XDP_PASS(orXDP_DROPif a global default-deny is configured).
Because BPF maps reside in kernel memory and the eBPF verifier guarantees bounded execution time, each packet consumes only a few hundred nanoseconds of CPU, even under multi-million-pps Mirai floods. The PAKKT agent synchronizes rule updates from the central panel every 30 seconds over mTLS, reloading the map atomically without dropping legitimate traffic.
For a deeper dive into PAKKT's architecture and third-party integrations, visit PAKKT Integrations, which documents the public API and Pterodactyl v1.x connector used by game-hosting providers.
Complementary nftables Rules for Stateful Mirai Mitigation
XDP excels at high-speed, stateless filtering—ideal for per-packet rate-limits and signature drops—but cannot track TCP connection state or enforce per-flow byte quotas. PAKKT deploys a complementary inet pakkt nftables table that operates on packets the XDP layer passes. Key rules include:
Connection Tracking and Invalid State Drop
nft add rule inet pakkt input ct state invalid drop
nft add rule inet pakkt input ct state established,related accept
This pair ensures that only packets belonging to an established flow or related ICMP errors reach the application, blocking stray ACKs and RSTs that Mirai sometimes sprays to exhaust conntrack slots.
SYN Rate-Limit per Source IP
nft add rule inet pakkt input tcp flags syn ct state new \
meter syn_flood { ip saddr timeout 10s limit rate over 20/second } drop
Even if XDP allows SYN packets that carry TCP options (legitimate clients), this meter prevents any single source from opening more than 20 new connections per second, mitigating slower, low-volume SYN floods that fly under the global PPS threshold.
Burst Tolerance with Token Bucket
nft add rule inet pakkt input tcp dport 25565 ct state new \
limit rate 100/second burst 200 packets accept
The burst keyword permits short spikes (player login waves) while capping sustained new-connection rates. The token bucket refills at 100 tokens/second, so legitimate traffic experiences no latency penalty, yet prolonged Mirai SYN floods cannot monopolize the accept queue.
Logging Anomalies without Performance Penalty
nft add rule inet pakkt input limit rate 10/minute log prefix \"[PAKKT-BLOCK] \" drop
Sampled logging (10 messages per minute) feeds the PAKKT audit log and GeoIP dashboard without flooding dmesg or syslog during peak attack periods. Operators can correlate top source countries and ASNs with known Mirai C2 infrastructure published by threat-intelligence feeds.
Because PAKKT provisions the inet pakkt table in its own netfilter namespace, these rules coexist peacefully with Docker's DOCKER-USER chain, fail2ban's dynamic IP bans, and any existing iptables-persistent configuration. There is zero risk of rule-order conflicts or accidental policy overwrite.
Real-World Deployment: Stopping a 15 Gbps Mirai Flood
A European game-hosting provider running 200+ Minecraft instances reported recurring 10–15 Gbps UDP floods targeting port 25565/udp (Bedrock query) and 19132/udp. Packet captures revealed 1024-byte payloads with no application-layer structure—classic Mirai UDP spam. Before PAKKT, the floods saturated the 10 GbE uplink and triggered null-routing at the datacenter edge, causing 15–20 minute outages twice per week.
The mitigation strategy deployed via PAKKT.io dashboard:
| Rule | Protocol | Port | Size Range | Action | Rate Limit |
| 1 | UDP | 25565 | 900–1100 bytes | block | — |
| 2 | UDP | 19132 | 900–1100 bytes | block | — |
| 3 | UDP | 25565 | 1–899 bytes | rate_limit | 50,000 pps |
| 4 | UDP | 19132 | 1–899 bytes | rate_limit | 50,000 pps |
Rules 1 and 2 dropped the bulk of the Mirai payload signatures at line rate in XDP. Rules 3 and 4 allowed legitimate query traffic (typically 20–200 bytes) up to a generous 50k pps ceiling, well above normal player query load. Complementary nftables rules enforced conntrack state and per-IP SYN limits for TCP traffic on port 25565/tcp (Java Edition).
Outcome: CPU load on the host remained below 8 percent during subsequent 12 Gbps floods; no packets reached the Java server process that matched the Mirai signature. Null-route incidents dropped to zero over a six-month observation window. The provider expanded PAKKT coverage to all edge nodes at a total cost of €600/month for 200 agents, far below the previous incident-response and redundant-uplink expenses.
Tuning XDP Maps and Avoiding False Positives
Effective Mirai mitigation requires continuous refinement of packet-size windows and rate-limit thresholds. PAKKT's per-rule metrics (stored in TimescaleDB and displayed on the real-time dashboard) show:
- Packets matched: how many packets hit each rule.
- Packets dropped: subset of matched packets that exceeded rate-limit or triggered a block action.
- Bytes matched: useful for estimating bandwidth savings.
Operators should review these metrics weekly and adjust size ranges if legitimate traffic patterns change. For example, a Minecraft modpack that introduces a new server-list ping payload of 950 bytes would suddenly appear in the 900–1100 byte block rule; the operator can either narrow the rule to 1000–1100 bytes or whitelist the source IPs of known server-list services.
Whitelist and blacklist synchronization occurs in both XDP (BPF map) and nftables (named sets), so an IP added to the whitelist via the PAKKT dashboard will bypass both layers within 30 seconds. This dual-layer design prevents race conditions where an IP is blocked in XDP but allowed in netfilter, or vice versa.
When debugging, use bpftool to inspect live map contents:
bpftool map dump name pakkt_rules
bpftool map dump name pakkt_whitelist
Each entry shows the key (rule ID or IP address) and value (action, rate-limit counters, timestamps). This transparency helps operators confirm that dashboard changes have propagated to the kernel and that rate-limit buckets reset as expected.
Future-Proofing Against Mirai Evolution
Botnet authors continuously test new evasion techniques: randomizing payload sizes, adding minimal TCP options to mimic browser stacks, and switching protocols mid-attack. Three strategies keep XDP defenses resilient:
Template Marketplace and Community Signatures
PAKKT's public API allows security researchers and hosting communities to publish and share rule templates. When a novel Mirai variant emerges, a template contributor can encode its signature—port, protocol, size range, rate-limit—and other users can import it with one click. This crowd-sourced intelligence accelerates response times from weeks to hours.
Layered Rate-Limits
Combine global max_pps (enforced across all rules) with per-port max_port_pps and per-rule rate-limits. A Mirai campaign that rotates through fifty UDP ports will still hit the global PPS ceiling, even if each individual port stays below its dedicated threshold.
Hybrid XDP + nftables Logic
Reserve XDP for high-volume, stateless decisions (IP blacklist, packet size, global PPS) and delegate stateful, low-volume logic (TCP handshake validation, per-connection byte quotas) to nftables. This division of labor ensures that the XDP program remains small enough to pass the eBPF verifier's complexity limits (4096 instructions in older kernels, 1M in recent versions) while still covering the attack surface that matters most.
For additional context on kernel-level defense patterns and emerging botnet trends, consult the Netfilter project documentation, which provides authoritative guidance on conntrack tuning and nftables meter semantics.
Conclusion
Mirai and its descendants remain a persistent threat in 2026, but kernel-level XDP filtering delivers the earliest and most resource-efficient interception point for their signature-based floods. By parsing Ethernet, IP, and transport headers in the NIC driver context and applying BPF map-driven rules before socket-buffer allocation, operators can drop millions of malicious packets per second with sub-microsecond latency and negligible CPU overhead. Complementary stateful nftables rules close the gaps that stateless XDP cannot address, creating a defense-in-depth posture that withstands both volumetric and low-and-slow Mirai campaigns without collateral damage to legitimate traffic.
FAQ
Can XDP distinguish between legitimate UDP game queries and Mirai UDP floods on the same port?
Yes, by filtering on packet size ranges and rate-limits. Legitimate game-server queries (Source Engine, Minecraft Bedrock) are typically 20–200 bytes, whereas Mirai floods use fixed 512, 768, or 1024-byte payloads. Create one XDP rule that blocks the Mirai size window and a second rule that rate-limits the legitimate range to a threshold above normal player query load.
How does PAKKT's dual-layer IP whitelist prevent false positives during a Mirai attack?
When you add an IP to the whitelist via the PAKKT dashboard, the agent updates both the XDP BPF map and an nftables named set within 30 seconds. Whitelisted IPs bypass all block and rate-limit rules in both layers, ensuring that trusted sources—monitoring probes, CDN health checks, partner APIs—never experience dropped packets even under sustained flood conditions.
What kernel version is required to run PAKKT's XDP engine against modern Mirai variants?
PAKKT requires Linux kernel 5.0 or higher with XDP support compiled in (CONFIG_XDP_SOCKETS=y). Most distributions since 2020—Ubuntu 20.04 LTS, Debian 11, Rocky Linux 8—ship compatible kernels by default. You can verify XDP availability by running ip link set dev eth0 xdp off; if the command succeeds without error, your kernel supports XDP and can load the PAKKT engine.
Deploy PAKKT in 30 seconds
Dual-layer kernel protection. XDP + nftables. Driven from a central panel. 7-day free trial.