InfraGuard

IP Connections

Host view of remote peer IPs per server as port-strength dots, with an IP investigation popup covering connection breakdown, rollup history, geo/ASN, reputation, and a block deeplink.

Overview — what it does

IP Connections is the second screen of Infrastructure ▸ Connectivity & Traffic (the host view). Where Port Connections pivots on "port → server", this screen pivots on "server (host) → remote peer IP". Each server card lists the remote IPs currently connected to that server, ranked by connection strength, and shows a per-monitored-port session-strength dot for every IP. The goal is to see at a glance which IP hits which server on which port, and how hard.

Clicking a peer IP opens the shared IP investigation popup, where you can examine that IP's connection breakdown (which server / port / TCP state / session count), a rollup connection-history sparkline, geo/ASN/ISP enrichment, an external reputation link, and a block deeplink into the Blocklist — all in one place.

All data is read read-only from the legacy traffic DB (legacy_glory). This screen never writes anything — write actions such as blocking are handed off via a popup deeplink to the Blocklist screen, where the write happens.

When to use

Layout

Hero · timer

The top-right holds the timer toggle (1 min / 5 min / 1 hour) that sets the display window, the latest snapshot timestamp, and a manual refresh button. The timer is the length of the query window anchored to the latest snapshot.

timer Query window
1 (default) The single latest snapshot minute
5 Last 5 minutes from the latest snapshot
60 Last 60 minutes from the latest snapshot

The chosen timer persists to localStorage['infr:timer:traffic-ips'] across visits. Only 1/5/60 are allowed; anything else is coerced to 1.

Strength legend + server chips

Server (host) cards

One card per selected server. The header shows the hostname and the peer count; the body is a table.

Cards are drag-reorderable via the grip (order persists to infr:order:traffic-ips), re-flowed with row-span masonry, and paginated 20 at a time.

Port strength dot colors

Sessions Token Color Meaning
0 none faint Not connected on this port
1–9 good green Low strength
10–49 warn amber Medium strength
50+ crit red High strength

IP investigation popup

Driven by the shared mixin mixins/ip_detail.js + partial infra/partials/ip-detail-modal.blade.php. It has two modes.

  1. sources mode — the list of source IPs in a (server, port) window. Entered from the SRC circle on Port Connections.
  2. investigate mode (this screen's default entry) — a single-IP deep dive. Entered by clicking a peer row.

What investigate mode shows:

Area Content Source
Summary KPI Total sessions · server count · port count · first/last seen ipSeenSpan() (full-retention MIN/MAX(created_at))
Geo Country · city · ASN · ISP ip_info_loop (ipEnrichment())
Connection history grain (5min / 1hour / 1day) sparkline rollup tables (ipHistory())
Connection breakdown Server × port × TCP state sessions · remote ports · first/last traffic_session_ct (ipBreakdown())

Popup footer actions (investigate): Copy IP · View IP (re-investigate on this page via ?src_ip=) · Reputation ↗ (external AbuseIPDB, new tab) · Block IP (deeplink to Blocklist via ?add=).

The popup's Reputation ↗ button is a plain link that opens the external abuseipdb.com/check/… in a new tab. The in-app reputation popup that shows a confidence gauge and report history inside the console is a Security-screen feature — see IP Reputation.

How to use

Basic flow

  1. Set the window (1/5/60 min) with timer. Shorter is closer to "connected right now".
  2. Narrow to the servers you care about with server chips (all by default).
  3. On a server card, look for peers with a red strength dot (50+ sessions) or peers spanning multiple ports.
  4. Click the suspect peer row to open the investigation popup.
  5. In the popup use the connection breakdown to see which server/port/state it hit, the history to gauge persistence (one-off vs recurring), and geo/ASN for origin.
  6. If needed, check external report history via Reputation ↗, and if malicious hand it to the Blocklist with Block IP.

Switching history grain

Switching grain in the popup's history section changes the rollup table. The default grain is hourly (1hour) — the best density/speed balance.

5min    → traffic_session_ct_5min   · individual IP · latest-snapshot −6h window
1hour   → traffic_session_ct_1hour  · individual IP · latest-snapshot −3d window   (default)
1day    → traffic_session_ct_1day   · /24 block     · latest-snapshot −120d window

Daily (1day) history is aggregated by the IP's /24 block (first 3 octets, 256 IPs), not the individual IP — because the rollup collector stores _1day by C-class. The popup then displays a CIDR scope label such as 211.224.128.0/24 to make the scope explicit. 5min and 1hour use the individual IP as-is.

Deeplinks

/infra/traffic/ips?src_ip=203.0.113.10
/infra/traffic/ips?servers=glory,blue

Polling

The page polls /infra/traffic/ips/live every 30 seconds to auto-refresh (not Reverb — the collector writes to the DB outside Laravel, so polling is the sensible choice). On refresh, if all were selected it auto-includes newly appearing servers, and drops servers that vanished from the selection.

Data sources

Window anchoring

The display window is anchored to the data's latest snapshot (MAX(snapshot_ts)), not the app's now(). The collector's storage clock can drift up to ~9 hours behind the app clock, so a now()-based window would fall outside the data and render empty.

Host view query (ipPeers)

-- TrafficRepository::ipPeers (parameter-bound)
SELECT server_name, remote_ip, local_port, SUM(session_count) AS total_sessions
  FROM traffic_session_ct
 WHERE snapshot_ts BETWEEN :min AND :max
   AND local_port IN (:ports)          -- OpsPolicy::monitoredPorts()
 GROUP BY server_name, remote_ip, local_port;

The monitored ports are not hardcoded — they come from infra_monitored_ports (CSV) in Operations Policy. The ipsData() result is cached for 20 seconds (key infr:traffic:ips:v1:{timer}:{ports}).

Investigation popup queries

Method Table What it does
ipSeenSpan() traffic_session_ct MIN/MAX(created_at) = true observation span (≈8h retention), MAX(snapshot_ts) = the IP's own latest batch (breakdown anchor)
ipBreakdown() traffic_session_ct Per server×port×state session sums · remote ports · first/last (LIMIT 200)
ipHistory() 3 rollups Session history per grain (LIMIT 400)
ipEnrichment() ip_info_loop Country · city · ASN · ISP (graceful null if absent)

The connection breakdown is anchored to the IP's own latest snapshot batch, not the global latest window. This is deliberate so an IP that isn't connected right now but hit us in the past still shows its distribution, reconstructed from its last observed moment.

Rollup index caveat (performance-critical)

ipHistory() always specifies direction IN ('inbound','outbound').

-- _1day uses the composite index t_ip(direction, remote_ip).
-- Without an explicit direction it scans the created_at range only → 12s+.
-- With it, the index engages → ~20ms (measured 2026-08-06).
SELECT created_at, SUM(session_count) AS sessions
  FROM traffic_session_ct_1day
 WHERE direction IN ('inbound','outbound')
   AND remote_ip = :cclass_key           -- daily uses the /24 first-3-octet key
   AND created_at >= :since
 GROUP BY created_at
 ORDER BY created_at
 LIMIT 400;

The rollups are huge (_5min ≈ 209M · _1hour ≈ 112M · _1day ≈ 24M), so a tight created_at >= window + LIMIT is mandatory. Popup results are protected by caches: investigate 25s, sources 20s.

Access

Troubleshooting & FAQ

Cards are empty and only "no peers in this window" shows. It means the latest snapshot has no connections on the monitored ports. (1) Widen timer to 5 or 60, (2) confirm real service ports are registered in Operations Policy infra_monitored_ports, and (3) check that recent snapshots are landing in traffic_session_ct (collector check_ct.js).

Everything is empty and there is no snapshot timestamp. Likely the legacy_glory connection or traffic_session_ct itself is empty. Verify the legacy_glory DB credentials in .env and that the traffic collector is running. On a query failure the payload carries error:true.

Only the daily history shows "no daily rollup history for this /24 block". Daily aggregation can lag by a day and is keyed by the /24 block. Check the 5min and hourly grains first. If the block has no rollup yet, this is expected.

I clicked an IP but the connection breakdown is empty. That IP has no sessions in the recent snapshot but has past observations. Use the summary KPI first/last seen and the connection history to confirm past activity (the breakdown reconstructs from the IP's last snapshot batch).

The popup's "Reputation ↗" opens a new tab instead of showing inline. That is intended. This traffic popup uses an external AbuseIPDB link. To see the confidence gauge and report history inside the console, use the Security screens' in-app reputation popup.

What drives the strength dot colors? The per-port session-count bucket — 1–9 green · 10–49 amber · 50+ red · 0 is a faint dot. Only the first 8 monitored ports are shown as columns.

Related

IP connections — remote peers per server
IP connections — remote peers per server