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/main.cpp | 105 +++++------------------------------------------------------ 1 file changed, 8 insertions(+), 97 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 31fca73..72dd267 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,12 +48,8 @@ #include #include "wireframe/capture_session.hpp" -#include "wireframe/l7/http.hpp" -#include "wireframe/net/checksum.hpp" -#include "wireframe/net/ethernet.hpp" -#include "wireframe/net/ipv4.hpp" -#include "wireframe/net/tcp.hpp" #include "wireframe/net/tcp_reassembly.hpp" +#include "wireframe/packet_diagnostics.hpp" #include "wireframe/search.hpp" #include "wireframe/summarize.hpp" @@ -72,95 +68,6 @@ void hex_dump(std::span bytes) { std::printf("\n"); } -// -c only: checksum validation isn't part of summarize_packet()'s -// shared output (see wireframe/net/checksum.hpp for why - checksum -// offload makes it noise, not signal, on most of the interfaces this -// project has actually been tested against). IPv4 only for now; this -// does its own minimal walk down to the IP/TCP/UDP byte spans the -// checksum functions need, reusing the existing decoders rather than -// duplicating their parsing logic. -std::string checksum_status(std::span bytes, int datalink) { - std::span ip_bytes; - if (datalink == DLT_RAW) { - ip_bytes = bytes; - } else { - auto eth = wireframe::net::parse_ethernet(bytes); - if (!eth || eth->header.ethertype != wireframe::net::kEthertypeIPv4) return ""; - ip_bytes = eth->payload; - } - if (ip_bytes.empty() || (ip_bytes[0] >> 4) != 4) return ""; // only IPv4 checksums, for now - - auto ip = wireframe::net::parse_ipv4(ip_bytes); - if (!ip) return ""; - - std::size_t header_len = static_cast(ip->header.ihl) * 4; - std::string out = " checksums: IP="; - out += wireframe::net::verify_ipv4_checksum(ip_bytes.first(header_len)) ? "ok" : "BAD"; - - using wireframe::net::ChecksumResult; - if (ip->header.protocol == wireframe::net::kProtoTcp) { - auto result = - wireframe::net::verify_tcp_checksum_ipv4(ip->header.src, ip->header.dst, ip->payload); - out += result == ChecksumResult::kValid ? " TCP=ok" : " TCP=BAD"; - } else if (ip->header.protocol == wireframe::net::kProtoUdp) { - auto result = - wireframe::net::verify_udp_checksum_ipv4(ip->header.src, ip->header.dst, ip->payload); - out += result == ChecksumResult::kValid ? " UDP=ok" - : result == ChecksumResult::kNotPresent ? " UDP=none" - : " UDP=BAD"; - } - return out; -} - -// -a only: TCP stream reassembly (wireframe/net/tcp_reassembly.hpp), -// re-run through the same HTTP dissector summarize_packet() already -// uses for a single segment - reassembly only helps when a message is -// actually split across packets, and HTTP is the L7 dissector in this -// project that's structured around lines/headers rather than one fixed -// datagram (DNS/TLS ClientHello are each their own single UDP datagram -// or first TCP segment already). Printed as its own line rather than -// folded into the per-packet summary: it reflects accumulated flow -// state, not just this one packet. In-order-only reassembly (see the -// header's own comment) means this can legitimately fire again on a -// later packet of the same request with an unchanged result once the -// headers are already complete - an honest simplification, not -// deduplicated further. -std::optional reassembled_http_status(std::span bytes, - int datalink, - wireframe::net::TcpReassembler& reassembler) { - std::span ip_bytes; - if (datalink == DLT_RAW) { - ip_bytes = bytes; - } else { - auto eth = wireframe::net::parse_ethernet(bytes); - if (!eth || eth->header.ethertype != wireframe::net::kEthertypeIPv4) return std::nullopt; - ip_bytes = eth->payload; - } - if (ip_bytes.empty() || (ip_bytes[0] >> 4) != 4) return std::nullopt; // IPv4 only, for now - - auto ip = wireframe::net::parse_ipv4(ip_bytes); - if (!ip || ip->header.protocol != wireframe::net::kProtoTcp) return std::nullopt; - - auto tcp = wireframe::net::parse_tcp(ip->payload); - if (!tcp) return std::nullopt; - - auto reassembled = reassembler.process_segment(ip->header.src, tcp->header.src_port, - ip->header.dst, tcp->header.dst_port, - tcp->header.seq, tcp->header.flags, - tcp->payload); - if (!reassembled) return std::nullopt; - - auto http = wireframe::net::parse_http(*reassembled); - if (!http) return std::nullopt; - - std::string out = " [reassembled "; - out += http->is_request ? "request] " : "response] "; - out += http->method_or_version + " " + http->target_or_status; - if (http->host) out += " Host: " + *http->host; - out += " (" + std::to_string(reassembled->size()) + " bytes so far)"; - return out; -} - struct RenderOptions { bool verbose_hex; bool verbose_checksums; @@ -185,11 +92,15 @@ void render_packet(const wireframe::CapturedPacket& packet, const RenderOptions& if (!wireframe::matches_search(line, opts.search_term)) return; - if (opts.verbose_checksums) line += checksum_status(bytes, opts.datalink); + if (opts.verbose_checksums) { + std::string status = wireframe::checksum_status(bytes, opts.datalink); + if (!status.empty()) line += " " + status; + } std::printf("%s\n", line.c_str()); if (opts.reassembler) { - if (auto status = reassembled_http_status(bytes, opts.datalink, *opts.reassembler)) { - std::printf("%s\n", status->c_str()); + if (auto status = wireframe::reassembled_http_status(bytes, opts.datalink, + *opts.reassembler)) { + std::printf(" [%s]\n", status->c_str()); } } if (opts.verbose_hex) hex_dump(bytes); -- cgit v1.2.3