meerkat: A Suricata Console That Shows You Sources, Not Alerts

Kicked TeamMay 15, 20266 min read

Suricata is a superb sensor and a terrible conversationalist. Point it at an internet-facing interface with a standard ruleset and it will tell you, individually and at length, about every packet that offends it. The signal is in there — but nobody's attention survives the volume.

meerkat is our answer, now open source under the 0BSD license. It is named for Suricata suricatta — the meerkat, the sentry that stands watch and alarm-calls. It runs on the router next to Suricata itself, and its home page is not a list of events. It is a list of source addresses.

The argument, with numbers

Here is a four-minute window measured on a live edge router: 891 alerts, broken down by category:

share category what it is
68.8% ET CINS "source is on a reputation list"
16.3% ET DROP Dshield blocklist, same idea
10.6% GPL ICMP someone pinging
2.6% SURICATA engine events (invalid ack, checksums)
1.4% ET SCAN actual scanning
0.3% ET COMPROMISED actual compromise indicator

We tried piping this to a chat channel. It flooded the channel in minutes, and the two categories that actually matter — the bottom two rows — scrolled past unread with the rest.

The tempting lesson is "filter harder." We think that is the wrong lesson. The volume is not a bug in the ruleset; reputation-feed hits are genuinely worth recording, just not worth an individual notification each. The real lesson is that a chat channel is the wrong tool. An alert stream answers "what just happened?" — but the question an operator actually has is "who is doing something to me, and what am I going to do about them?"

Rolled up per source address, those 891 rows become a few dozen. Each row is a decision: block, acknowledge, allowlist, or ignore. That is the whole product. Everything else follows from it.

What it does

meerkat follows Suricata's eve.json, enriches every alert with ASN, country, and city, and stores it all in SQLite on the box. The web UI serves:

  • Sources, rolled up — first and last seen, alert count, which signatures tripped, which ports were probed, worst severity, and current state. Filter by country, AS, port, signature, severity, state, time window, or minimum volume.
  • One source, everything known — drill into an address and see what it tripped, when, against which ports, and what an operator did about it, on a timeline.
  • Actions with accountability — block, unblock, acknowledge, or allowlist, one source or in bulk, always with a reason and an expiry.
  • A ruleset you can reason about — the whole installed Suricata catalogue, joined to what each rule has actually cost you in alert volume. Enable or disable a rule or category, override a severity, set per-signature dispositions — notify, digest, or mute the reputation feeds in one click. Changes are applied by rebuilding with suricata-update and reloading live, then read back from disk, so the UI reflects what the sensor is really running.

Why a block is an nftables call, never a Suricata drop

meerkat can block a source, but it never does it by flipping a Suricata rule to drop. The block is a call to nftables, the firewall that is already in the traffic path.

We think this separation is right, and worth being opinionated about:

  • The sensor stays a sensor. The moment Suricata becomes the enforcement point, every ruleset reload is a traffic-affecting change, and every engine hiccup is an outage. Detection and enforcement have different reliability requirements; coupling them means both inherit the worse of each.
  • Blocks stay auditable. A firewall rule created with a reason and an expiry is an operator action you can list, review, and unwind. A drop buried in a 40,000-signature ruleset is not.
  • The firewall is better at it. Dropping traffic from an address is a one-line kernel decision. Asking a deep-packet-inspection engine to do a job a set lookup can do is the wrong tool again — the same mistake as the chat channel, in the other direction.

Small, local, on the router

Like the rest of our tooling, meerkat is a single Go binary that runs on the router itself — no agent, no cloud, no pipeline shipping your alert data to someone else's SIEM before you can read it. The data stays on the box that produced it, which also means it works fine on the metered or modest uplinks where edge routers actually live.

It is beta software. Expect bugs; it has not yet had the testing a piece of security infrastructure deserves. Read the cautions in the README before you install it.

If you want to see what this class of edge data looks like in practice, our public threat map shows detections from the AS210622 edge.

How it was built

meerkat is the third tool we have shipped this year with AI coding agents writing most of the implementation under human design and review. The core judgment calls — sources over events, nftables over Suricata drops, SQLite on the box over a cloud backend — were made by people; the agents made building it fast enough to be worth doing. The full story is in our case study on building three tools with agentic development.

Takeaways

  1. Aggregate to the unit of decision. Operators decide about sources, not packets — so the UI's first page is sources.
  2. Volume is data too. Reputation-feed hits belong in the database, not in your notifications.
  3. Keep detection and enforcement separate. The sensor watches; the firewall blocks; each does its job well.

If your edge is noisy and nobody is actually reading the alerts, we can help — and if you run Suricata on a router somewhere, give meerkat a try and tell us what breaks.