From fbedc55d5aa861c381701c9f913b34ee7ab57ec4 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Tue, 21 May 2024 22:24:00 +0200 Subject: Add GUI parity for -c/-a, mDNS/SSH dissectors, and two new fuzz harnesses GUI parity: checksum_status()/reassembled_http_status() moved out of main.cpp into a shared wireframe/packet_diagnostics.hpp so the GUI can show the same -c/-a diagnostics for the selected packet without duplicating the Ethernet/IPv4/TCP walk. Visually verified under Xvfb with the same split-segment scenario used to verify -a on the CLI. Two new L7 dissectors: mDNS (reuses parse_dns outright - RFC 6762 keeps DNS's wire format, just a different port) and SSH's cleartext identification banner. Live-verified against this machine's real sshd and a real DNS-wire-format packet sent to port 5353. Two new fuzz harnesses (fuzz_checksum, fuzz_tcp_reassembly) covering code added here that the original nine harnesses never touched. All 12 run clean across ~90M executions with no crashes. NAMES.md and PLAN.md updated with this round's decisions and naming candidates. --- src/gui_main.cpp | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'src/gui_main.cpp') diff --git a/src/gui_main.cpp b/src/gui_main.cpp index 16ee769..8a7771a 100644 --- a/src/gui_main.cpp +++ b/src/gui_main.cpp @@ -23,6 +23,8 @@ #include #include "wireframe/capture_session.hpp" +#include "wireframe/net/tcp_reassembly.hpp" +#include "wireframe/packet_diagnostics.hpp" #include "wireframe/search.hpp" #include "wireframe/summarize.hpp" @@ -31,6 +33,11 @@ namespace { struct PacketRow { std::string summary; std::vector data; + // -a only: computed once at consume time (reassembly needs + // in-order state across packets, unlike checksum status below, + // which is stateless and cheap enough to compute lazily when a row + // is selected instead of storing it on every row). + std::optional reassembled_http; }; constexpr std::size_t kMaxRows = 5000; // cap memory; oldest rows scroll off @@ -52,7 +59,7 @@ struct SharedState { }; void consumer_loop(wireframe::CaptureSession& session, wireframe::CaptureQueue& queue, - SharedState& state) { + SharedState& state, wireframe::net::TcpReassembler* reassembler) { while (auto packet = queue.pop()) { std::span bytes{packet->data}; std::string summary = wireframe::summarize_packet(bytes, session.datalink()); @@ -62,8 +69,15 @@ void consumer_loop(wireframe::CaptureSession& session, wireframe::CaptureQueue& packet->original_len); } + std::optional reassembled_http; + if (reassembler) { + reassembled_http = wireframe::reassembled_http_status(bytes, session.datalink(), + *reassembler); + } + std::lock_guard lock(state.mutex); - state.rows.push_back({std::move(summary), std::move(packet->data)}); + state.rows.push_back({std::move(summary), std::move(packet->data), + std::move(reassembled_http)}); if (state.rows.size() > kMaxRows) state.rows.pop_front(); ++state.packet_count; } @@ -89,6 +103,11 @@ void print_usage(const char* argv0) { " -r Replay a saved pcapng file instead of a live device\n" " -f Kernel-level capture filter (tcpdump/BPF syntax); also\n" " applies to what -w writes. Can't be combined with -r.\n" + " -c Show IPv4/TCP/UDP checksum validity for the selected packet.\n" + " Off by default - see the CLI's -h for why (checksum offload).\n" + " -a Reassemble TCP streams and show HTTP requests/responses\n" + " joined across segments for the selected packet, when its\n" + " segment contributed to one. In-order segments only.\n" " -h, --help Show this help and exit\n" "\n" "Examples:\n" @@ -109,6 +128,8 @@ int main(int argc, char** argv) { } wireframe::CaptureSessionOptions options; + bool enable_checksums = false; + bool enable_reassembly = false; for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "-w") == 0 && i + 1 < argc) { options.pcapng_output_path = argv[++i]; @@ -116,6 +137,10 @@ int main(int argc, char** argv) { options.filter_expr = argv[++i]; } else if (std::strcmp(argv[i], "-r") == 0 && i + 1 < argc) { options.replay_input_path = argv[++i]; + } else if (std::strcmp(argv[i], "-c") == 0) { + enable_checksums = true; + } else if (std::strcmp(argv[i], "-a") == 0) { + enable_reassembly = true; } else if (options.device.empty()) { options.device = argv[i]; } @@ -158,9 +183,10 @@ int main(int argc, char** argv) { wireframe::CaptureQueue queue(4096); SharedState state; + wireframe::net::TcpReassembler reassembler; std::thread capture_thread = session.start_capture_thread(queue); std::thread consumer_thread(consumer_loop, std::ref(session), std::ref(queue), - std::ref(state)); + std::ref(state), enable_reassembly ? &reassembler : nullptr); int selected_row = -1; bool quit = false; @@ -248,7 +274,18 @@ int main(int argc, char** argv) { { std::lock_guard lock(state.mutex); if (selected_row >= 0 && selected_row < static_cast(state.rows.size())) { - for (const auto& line : wireframe::hex_dump_lines(state.rows[selected_row].data)) { + const auto& row = state.rows[selected_row]; + if (enable_checksums) { + std::string status = wireframe::checksum_status(row.data, session.datalink()); + if (!status.empty()) { + ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, 1.0f), "%s", status.c_str()); + } + } + if (row.reassembled_http) { + ImGui::TextColored(ImVec4(0.6f, 1.0f, 0.6f, 1.0f), "%s", + row.reassembled_http->c_str()); + } + for (const auto& line : wireframe::hex_dump_lines(row.data)) { ImGui::TextUnformatted(line.c_str()); } } else { -- cgit v1.2.3