Project 01 / 04
mirage
Adaptive network deception for Linux.
Context
Why it exists
Firewalls, IDS alerts and honeypots all try to answer one question about suspicious traffic: what is this host doing? mirage explores a second one: what should this host be allowed to believe exists?
The long-term goal is one real network with many perceived networks — a scanning host might find services and machines that do not exist, while the real infrastructure stays hidden. Detection and adaptation are meant to be deterministic: rules, behavioural scoring and state machines, with no machine learning.
The project is deliberately staged. Deception comes only after the telemetry and behavioural foundations are stable, so Phase 1 is about seeing reconnaissance clearly.
Architecture
Phase 1 pipeline, as implemented
- 01
Capture
libpcap, live from an interface or replayed from a pcap file
- 02
Decode
IPv4 and IPv6 TCP packets; SYN-without-ACK only
- 03
Classify
Direction relative to this host: inbound, outbound, local, transit
- 04
Session
Inbound events grouped per remote host: ports, hit counts, first-touch order
- 05
Emit
JSON-lines telemetry and a loopback-only inspection API
Observe · Built
Replaying the test capture
mirage ships a generator for a synthetic capture so its behaviour can be checked without root. Step through it to see how each packet is treated and how inbound traffic becomes one session per remote host.
- captured
- 209
- filtered
- 1
- sessions
- 4
Step 6 of 6. From 192.168.1.10 to 203.0.113.5: A SYN-ACK reply. Not a connection attempt: counted as filtered and dropped.
Sessions · one per remote host
| id | remote_ip | events | distinct_ports |
|---|---|---|---|
| 1 | 203.0.113.5 | 200 | 200 |
| 2 | 198.51.100.7 | 3 | 1 |
| 3 | 198.51.100.20 | 1 | 1 |
| 4 | 2001:db8::bad | 4 | 4 |
A reconstruction of the fixture in tools/genpcap, not output captured from mirage. The totals match the result documented in its README.
Decisions
Key decisions
01
SYN filtering happens in code, not in BPF
libpcap's tcp[tcpflags] syntax does not work for IPv6, so the BPF filter only narrows to TCP and the SYN-only check runs during capture. Both address families take the same path.
02
The inspection API refuses public interfaces
Session data shows exactly who is scanning the host, so the HTTP API only binds to loopback addresses. Telemetry files are created with mode 0640.
03
Deterministic and replayable
A bundled generator writes a synthetic capture; replaying it needs no root and produces the same output on every run apart from timestamps. Tests run under the race detector.
04
Bounded by design
Concurrent sessions are capped at 10,000, idle sessions are swept every 10 seconds, and a session closes after a configurable idle timeout (5 minutes by default).
Progress
Built, and still to build
- BuiltObserve — capture, sessions, telemetry
- NextDetect — score session behaviour
- PlannedDeceive — fake services for flagged sessions
- PlannedMutate — per-observer, evolving topologies
- PlannedVisualize — sessions and perceived networks
Concept
One network, many perceived networks
This is where mirage is heading: one real network, and a different picture of it for whoever is scanning. Play it through, or step between stages.
05 Diverge
- real hosts
- 27
- scanner sees
- 31
- phantom
- 6
- hidden
- 2
MutateSome real hosts drop out of the scanner's view. The network it maps no longer matches the one that exists.
- real host
- probed
- phantom host
- hidden from scanner
The first three stages show what mirage does today. Deceive and Mutate are planned phases; mirage does not do this yet.
Limitations
Known limitations
- Only TCP SYN packets are observed; UDP, ICMP and FIN/NULL/Xmas scans are not.
- Only inbound traffic forms sessions.
- Local addresses are read once at startup.