# Traffic Viewer - JSON Event Format The traffic viewer is now fully integrated. To enable structured event display, the NFProxy C++ binary (`backend/binsrc/nfproxy.cpp`) should emit JSON lines to stdout with the following format: ## JSON Event Schema ```json { "ts": 1701964234567, "direction": "in", "src_ip": "192.168.1.100", "src_port": 54321, "dst_ip": "10.0.0.5", "dst_port": 443, "proto": "tcp", "size": 1420, "verdict": "accept", "filter": "filter_sanitize", "sample_hex": "474554202f20485454502f312e310d0a486f73743a206578616d706c652e636f6d..." } ``` ## Fields - `ts` (required): Unix timestamp in milliseconds - `direction`: `"in"` (client→server) or `"out"` (server→client) - `src_ip`, `dst_ip`: Source and destination IP addresses - `src_port`, `dst_port`: Source and destination ports - `proto`: Protocol name (e.g., `"tcp"`, `"udp"`) - `size`: Packet/payload size in bytes - `verdict` (required): `"accept"`, `"drop"`, `"reject"`, or `"edited"` - `filter`: Name of the Python filter that processed this packet - `sample_hex`: Hex-encoded sample of payload (first 64-128 bytes recommended) ## Implementation Notes 1. **Backward Compatibility**: The parser in `firegex.py::_stream_handler` only processes lines starting with `{`. Non-JSON output (logs, ACK messages) continues to work as before. 2. **Performance**: Emit JSON only when needed. Consider an env flag: ```cpp bool emit_traffic_json = getenv("FIREGEX_TRAFFIC_JSON") != nullptr; if (emit_traffic_json) { std::cout << json_event << std::endl; } ``` 3. **Sample Code** (C++ with nlohmann/json or similar): ```cpp #include using json = nlohmann::json; void emit_traffic_event(const PacketInfo& pkt, const char* verdict, const char* filter_name) { json event = { {"ts", current_timestamp_ms()}, {"direction", pkt.is_inbound ? "in" : "out"}, {"src_ip", pkt.src_addr}, {"src_port", pkt.src_port}, {"dst_ip", pkt.dst_addr}, {"dst_port", pkt.dst_port}, {"proto", pkt.protocol}, {"size", pkt.payload_len}, {"verdict", verdict}, {"filter", filter_name}, {"sample_hex", hex_encode(pkt.payload, std::min(64, pkt.payload_len))} }; std::cout << event.dump() << std::endl; } ``` ## Testing Without Binary Changes The viewer works immediately—it will display "No traffic events yet" until the binary is updated. You can manually test the Socket.IO flow by emitting mock events from Python: ```python # In backend shell or script import asyncio import json from utils import socketio async def emit_test_event(): event = { "ts": int(time.time() * 1000), "direction": "in", "src_ip": "192.168.1.50", "src_port": 12345, "dst_ip": "10.0.0.1", "dst_port": 80, "proto": "tcp", "size": 512, "verdict": "accept", "filter": "test_filter" } await socketio.emit("nfproxy-traffic-YOUR_SERVICE_ID", event, room="nfproxy-traffic-YOUR_SERVICE_ID") ``` ## Current Features ✅ **Backend**: - Ring buffer stores last 500 events per service - REST endpoint: `GET /api/nfproxy/services/{id}/traffic?limit=500` - REST endpoint: `POST /api/nfproxy/services/{id}/traffic/clear` - Socket.IO channels: `nfproxy-traffic-{service_id}` for live events, `nfproxy-traffic-history` on join ✅ **Frontend**: - Live table view at `/nfproxy/{service_id}/traffic` - Client-side text filter (searches IP, verdict, filter name, proto) - Click row to view full event details + hex payload - Auto-scroll, clear history button - Accessible via new button (double-arrow icon) in ServiceDetails page ## Next Steps 1. Update `backend/binsrc/nfproxy.cpp` to emit JSON events as shown above 2. Rebuild the C++ binary 3. Start a service and generate traffic—viewer will populate in real-time 4. Optionally add more filters (by verdict, time range) or export to PCAP