InfraGuard

Port Connections (PORT OVERVIEW)

Flagship port monitoring screen showing per-port cards with per-server TCP-state distribution, top source IPs, and source counts, live.

Overview — what it does

Port Connections is the flagship screen of Infrastructure ▸ Connectivity & Traffic — the PORT OVERVIEW. It renders one card per monitored port (e.g. 80, 443, 22, 3306 …) defined in Operations Policy, and inside each card it breaks the TCP sessions bound to that port per server into a 100% stacked bar by state. The goal: scan "who is connected to this port right now, how many, in what state" in a single view.

The source is the legacy traffic DB (legacy_glory connection), table traffic_session_ct, populated periodically by the check_ct.js collector. The app is read-only here — this screen writes nothing.

Each server tile shows:

When to use

Layout

Top controls

Element Behavior
Timer 1min / 5min / 1hour Width of the session aggregation window. The choice persists to localStorage (infr:timer:traffic-ports) across visits.
Port chips The monitored-port list (Operations Policy). Click a chip to toggle its card on/off. All toggles select/deselect all. Filtering is session-only (not persisted) — the default on each new visit is always all ports.
Snapshot time The latest snapshot timestamp anchoring the current window (display-timezone corrected).
Refresh / polling Automatically polls /infra/traffic/ports/live every 30 seconds to refresh cards.

Port cards (masonry)

Cards are drag-reorderable, and the order is saved to localStorage (infr:order:traffic-ports). Because card heights vary, they lay out gap-free via row-span masonry (the sortable_masonry mixin). Within a card, server tiles sort by distinct source-IP count → total sessions → server index.

TCP state legend

Stack-bar colors come from semantic CSS tokens (var(--infr-state-*)). The legend maps color to state.

Token Label Meaning
established ESTABLISHED Normally established connection
listen LISTEN Listening (server socket)
syn_sent SYN SENT Connect attempt (client)
syn_recv SYN RECV SYN received / half-open — a surge suggests SYN flood
fin_wait FIN WAIT Closing (FIN_WAIT1/2 merged)
close_wait CLOSE WAIT Peer closed, app hasn't — a buildup signals connection leak
time_wait TIME WAIT Post-close wait
other Other Any state outside the seven above

How to use

  1. Pick a timer — use 1min for the tightest, most recent snapshot batch; 5min/1hour for smoother trends.
  2. Narrow to the ports you care about with chips — e.g. keep only 80·443 to watch web.
  3. Read the stack bar — a low ESTABLISHED share with large SYN_RECV/TIME_WAIT is an anomaly signal.
  4. Click the SRC circle — opens the source-IP list popup for that server·port (remote IP, remote ports, sessions, first/last seen).
  5. Click an IP → single-IP investigation — breaks down which servers·ports·states it hits, geo/ASN, and history (5min · hourly · daily rollup). From here you can proceed to reputation lookup or blocking.
  6. Reorder cards — drag frequently-watched ports to the top; the order is saved.

Daily (1day) history, due to the rollup design, aggregates by the IP's /24 range (256 IPs) rather than the individual IP. When the popup shows a CIDR label like by 211.224.128.0/24, that value is the sum across the whole range.

Data sources

Every query runs on the legacy_glory connection and is isolated in App\Repositories\TrafficRepository as parameter-bound query-builder calls (no string interpolation).

Window anchoring

The display window is anchored not to the app's now() but to the latest data snapshot (MAX(snapshot_ts)). The collector's write clock can lag the app clock by hours, so anchoring on now() would fall outside the data and yield a blank screen.

Timer SQL boundary (snapshot_ts)
1min startOfMinute … endOfMinute of the latest snapshot minute
5min startOfMinute of (latest − 4min) … latest endOfMinute
1hour startOfMinute of (latest − 59min) … latest endOfMinute

The snapshot_ts WHERE boundary uses the raw legacy stored time. Only the snapshot time shown on screen has the Operations Policy display offset (traffic_tz_offset_hours) added.

Core query — portOverview()

SELECT a.local_port, a.server_name, a.server_index, a.remote_ip,
       a.state_code, b.state_name,
       SUM(a.session_count) AS total_sessions
FROM traffic_session_ct AS a
LEFT JOIN protocol_state AS b ON a.state_code = b.state_code
WHERE a.snapshot_ts BETWEEN :min AND :max
  AND a.local_port IN (:ports)          -- Operations Policy monitored ports
GROUP BY a.local_port, a.server_name, a.server_index,
         a.remote_ip, a.state_code, b.state_name;

Related tables

Table Connection Role Fed by
traffic_session_ct legacy_glory Session snapshots (host/remote/state/count) check_ct.js
protocol_state legacy_glory TCP state code → name lookup —
traffic_session_ct_5min/_1hour/_1day legacy_glory Time-range history for the IP investigation popup aggregate.js
ip_info_loop legacy_glory Geo/ASN/ISP enrichment for the IP popup —

Server response shape (excerpt)

{
  "ports": [80, 443, 22],
  "timer": 1,
  "snapshot": "2026-08-13 10:24:00",
  "ports_data": [
    { "port": 443, "server_data": [
      { "alias": "web1", "idx": 12, "host_count": 84,
        "top_req": [ { "remote_ip": "203.0.113.10", "session_count": 61 } ],
        "connections": [ { "state": "established", "count": 420, "pct": 78 } ],
        "total": 538 }
    ] }
  ]
}

portsData() caches for 20 seconds (keyed by timer + a hash of the port list) to suppress remote round-trips.

Access

The Infrastructure role area is viewable at minimum user_level 1 (viewer). Port Connections is read-only, so there is no separate write gate — demo (1), staff (5), and admin (10) can all view it. The route requires only infr.auth session authentication.

Action Level required
View port connections, poll, open IP investigation popup 1 (any authenticated user)
Edit the monitored-port list (Operations Policy) 10 (Administration) — Operations Policy

The blocking action that follows from the IP investigation popup hands off to Security ▸ Blocklist, which requires write user_level 2+ and an audit log. This screen itself performs no blocking.

Troubleshooting & FAQ

Cards appear but server data is empty. No sessions were bound to that port in the window. Widen the timer to 5min/1hour, or verify the port is actually open with traffic.

All cards are empty with "No connection snapshot". traffic_session_ct on legacy_glory has no recent snapshot (the check_ct.js collector stopped, or the DB connection failed). If no latest snapshot time is shown, check the collector.

A port I want isn't shown. If it's not in the monitored-port list (infra_monitored_ports), no card is created. Add it as CSV in Administration ▸ Operations Policy (1–65535, max 30, input order preserved). Default:

infra_monitored_ports = 80,443,22,3306,25,465,27017,21,53,3030,8080,6379,6001

The snapshot time is off by several hours. When the legacy DB store clock differs from your display timezone, set traffic_tz_offset_hours (±14h) in Operations Policy to correct the displayed time. It is applied to display only, never to query boundaries.

Daily history is empty. The _1day rollup can lag by a day and aggregates by /24 range. Check the 5min or hourly grain instead.

Related

Port connections — the PORT OVERVIEW
Port connections — the PORT OVERVIEW