Skip to content

Add Chains and Capture tabs (v0.2.5)#5

Merged
ibehren1 merged 2 commits into
mainfrom
v0.2.5
Jul 16, 2026
Merged

Add Chains and Capture tabs (v0.2.5)#5
ibehren1 merged 2 commits into
mainfrom
v0.2.5

Conversation

@ibehren1

Copy link
Copy Markdown
Owner

Summary

Two new tabs for fwtop, both on the v0.2.5 branch.

Chains tab (key 4)

A chain-by-chain drill-down of firewall counters. A picker lists every table/chain in the ruleset (with rule count, highlighted red when actively dropping); selecting one shows that chain's rules in ruleset order — position, verdict, live pkt/byte rates, cumulative totals. Reads like nft list chain / iptables -L <chain>, complementing the drops-first Firewall tab.

Capture tab (key 5; Drops moved to 6)

An interactive, opt-in tcpdump. Press f to enter a port/protocol filter; fwtop captures just that traffic and shows three Overview-style stacked panels:

  • WAN / LAN throughput charts of the matched flow
  • a per-interface breakdown table
  • a live packet list in tcpdump's own format (HH:MM:SS.ffffff iface IP src.port > dst.port: …)

s stops capture.

Notes on the Capture design

  • First packet-capture source in the app. It shells out to the system tcpdump (one process per interface, matching how firewall.py shells out to nft/iptables) — no new Python dependency.
  • Strictly opt-in / low overhead: capture runs only while the tab is on screen; leaving the tab or unmounting stops it, so no tcpdump lingers and the rest of the app keeps its zero-capture footprint.
  • Reader daemon threads write to a lock-guarded buffer, drained on the UI timer (the existing Resolver threading model). WAN/LAN classification reuses is_private_ip; interface→zone reuses Config.zone_for.
  • Caveat: throughput is derived from captured frame lengths, so it approximates rather than exactly matches the Overview tab's kernel interface counters (documented in the README).

Verification

  • Headless Textual pilot tests (demo mode): all six tab keys switch correctly; interactive filter modal parses ports and starts capture; charts, interface table, and packet list all populate; s and leaving the tab both stop capture.
  • Unit-tested the tcpdump line parser against representative TCP/UDP/ICMP -e -tt -n output, and the BPF builder.
  • All modules compile clean.

⚠️ Not yet exercised against a live tcpdump (developed on macOS, demo-only). Worth a manual Linux/root check before relying on it: sudo fwtop, Capture tab, filter tcp port 443, confirm the panels track real traffic and pgrep tcpdump is empty after leaving the tab.

ibehren1 added 2 commits July 16, 2026 16:34
New ChainPanel widget with a chain picker (left) listing every
table/chain in the ruleset and a rules table (right) showing the
selected chain's rules in ruleset order — position, verdict, live
pkt/byte rates, and cumulative totals. Reads like `nft list chain` /
`iptables -L <chain>`, complementing the drops-first Firewall tab.

- app: new "Chains" TabPane, key 4 (Drops moved to 5), per-tick wiring
- demo: enrich synthetic ruleset to 4 chains with ordered rules
- css: border-title styling for #chain-panel
- README: keybindings, features, and Chains tab section
New opt-in Capture tab that behaves like an interactive tcpdump. Press
'f' to enter a port/protocol filter; fwtop then captures just that
traffic and shows three stacked panels (Overview-style): WAN/LAN
throughput charts of the matched flow, a per-interface breakdown table,
and a live packet list in tcpdump's own format. 's' stops capture.

This is the app's first packet-capture source and the only one that
captures packets. It shells out to the system tcpdump (one process per
interface, matching how firewall.py shells out to nft/iptables) and runs
only while the tab is on screen — leaving the tab or unmounting stops it,
so no tcpdump lingers and the rest of the app keeps its zero-capture
footprint. Capture runs on daemon reader threads writing to a
lock-guarded buffer, drained on the UI timer (the Resolver threading
model). WAN/LAN classification reuses is_private_ip; interface->zone
uses Config.zone_for. Throughput is derived from captured frame lengths,
so it approximates rather than matches the kernel interface counters.

- models: Packet + CaptureFilter (to_bpf/describe)
- sources/capture.py: CaptureSource (tcpdump backend + demo synthesizer)
- widgets: CapturePanel (charts + iface table + packet list),
  FilterModal (first value-returning modal in the app)
- app: Capture tab (key 5; Drops -> 6), f/s bindings, tab-driven
  lifecycle, refresh gated to the active tab
- tcss + README: styling, keybindings, features, capture caveat
@ibehren1 ibehren1 self-assigned this Jul 16, 2026
@ibehren1
ibehren1 merged commit cfec8b4 into main Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant