main
OneDrive's IPs (e.g. 13.107.x, 150.171.x) have no PTR and weren't in our CIDR table, so each fragmented into its own IP-named district — a long session showed dozens, all with the "OneDrive" process subtitle. Add the documented Microsoft 365 service ranges so they collapse to one Microsoft district. Deliberately excludes generic Azure tenant space, which would mislabel third-party apps hosted on Azure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NetworkCity
A macOS network monitor that renders live traffic as a top-down city map — remote hosts become buildings, and your traffic becomes cars driving to them (SimCity-style). This repo currently contains Phase 1: the proven data layer.
Architecture
ConnectionSource (protocol) ← the seam: "where bytes come from"
│
├─ NettopSource ← Phase 1: shells out to /usr/bin/nettop (no privileges)
└─ (libpcap source) ← Phase 2: real packets (needs privilege / helper tool)
│
▼
ConnectionSnapshot ← list of Connection, with cumulative byte counts
│
▼
SpriteKit "city" (Phase 3) ← buildings + cars; never knows the data source
The renderer depends only on NetworkCityCore, so the data backend can be
swapped without touching the visuals.
Layout
Sources/NetworkCityCore/— models, theConnectionSourceprotocol, thenettopparser (NettopParser, pure/testable) and poller (NettopSource).Sources/nettop-probe/— Phase-1 CLI proof of concept. Prints live KB/s.Tests/— parser tests pinned to real capturednettopoutput.
Try it
swift test # parser tests against real fixtures
swift run nettop-probe # live traffic, busiest external flows as KB/s
Key design facts (learned from real output)
- nettop format: process rows are
Name.PID,bytes_in,bytes_out; the connection sub-rows beneath inherit that process. IPv4 ports use:, IPv6 uses.and may carry a%zonesuffix. - Rates by diffing: byte counts are lifetime-cumulative, so we keep the last snapshot and subtract. Robust to nettop quirks; works across fresh invocations.
- Process names are unreliable — nettop truncates/mangles them (it reported
claudeas2.1.177). The pid is trustworthy; enrich the real name viaproc_pidpath/pskeyed on pid. (Phase-2 polish.) isExternalfilters listeners, loopback, and link-local so only real off-box destinations become buildings.
Roadmap
- ✅ Data layer + live probe (nettop, no privileges)
- ✅ SpriteKit city — SwiftUI window, glowing buildings, cars of light
(
swift run NetworkCityApp): cyan cars inbound = downloads, amber outbound = uploads; deterministic building placement; drag to pan, scroll to zoom. - ✅ Enrichment — real process names (
proc_pidpath), reverse-DNS + a curated CIDR table so hosts group into named districts (Apple, Google, AWS, Telegram, Local Network…). PTR is primary; the CIDR table catches the no-PTR giants (all of17.0.0.0/8is Apple). Run withNC_DEBUG=1to log each host→district resolution to stderr. - ✅ Hub-and-spoke — busy districts auto-expand into their endpoints
(
This Mac → OneDrive → its many servers); cars route the full two-segment path. Expansion is a pure, testedExpansionPolicy(≥2 endpoints, top-K by bytes, TTL tail to avoid flicker). A single client downloading from a CDN pins to one IP, so fan-out is driven by apps that genuinely spread connections (sync clients, browsers). - ✅ Traffic differentiation — cars coloured by protocol class (DNS gold,
HTTPS cyan, HTTP orange, QUIC violet, Other slate) since direction is already
read from motion. Behaviour reinforces it: DNS = tiny fast sparks, QUIC =
streaks, heavy flows = big slow "freight" comets. Classifier is a pure tested
TrafficClass; HUD shows a legend. - ✅ Label anti-overlap (
LayoutSolver). - ✅ Click-to-inspect — click a district hub to open a live panel: total down/up, every endpoint with its reverse-DNS name + per-endpoint rate + protocol-colour dot, and the owning process(es). Click empty space or ✕ to close. A pulsing ring marks the selection. Click vs drag is disambiguated by movement distance.
- ✅ Latency as distance — distance from downtown = measured round-trip time
(unprivileged TCP-connect probe, cached), not geography. GeoIP was rejected
because anycast makes it assert a physical fiction; latency is measured so it
can't lie. Districts glide to their true distance as probes complete; the
inspector shows per-endpoint ms. Pure
LatencyLayout(log curve) is tested;LatencyProberuses Network.framework. Our own pid is filtered out so we don't render our own probes. MenuBarExtrashell; optional libpcap source via privileged helper.
Env flags (opt-in diagnostics)
NC_DEBUG=1— log host→district resolution, per-tick top districts, and fan-outs to stderr.NC_DEMO=1— offline demo: feeds a synthetic 8-endpoint "OneDrive" through the real scene so the hub-and-spoke fan-out runs without nettop.
Description
Languages
Swift
100%