From 08332a4195956611db80a2cfe3710d760cbd6acf Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Tue, 14 May 2024 01:42:00 +0200 Subject: Initial commit: wireframe packet capture/analysis tool Terminal packet capture and analysis tool built to learn the C++ memory model (byte layout, alignment, endianness, std::span over unowned buffers) via a real capture pipeline. - Hand-rolled L2-L4 decoders (Ethernet, IPv4, IPv6 with extension header walking, TCP, UDP) over std::span, no struct-casting - L7 dissector interface with DNS, HTTP, and TLS SNI implementations - pcapng read/write for Wireshark-compatible capture files - Bounded capture queue: drop-on-backpressure for live capture, blocking push for faithful file replay - Kernel-level BPF filtering (-f) and a separate display-only search (-g / interactive) that doesn't touch what's captured - Replay mode (-r) reads a saved pcapng file back through the same pipeline as live capture, no root or live device needed - pcap_stats() surfaces kernel/interface drops invisible to the capture queue's own counter - Three frontends sharing one CaptureSession setup path: CLI, TUI (FTXUI, primary), GUI (Dear ImGui + SDL3, secondary) - 89 unit tests (doctest) plus 9 libFuzzer harnesses covering every hand-rolled parser; fuzzing found and fixed a real OOM in the pcapng reader (unbounded allocation from an untrusted length field) --- tests/test_dns.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tests/test_dns.cpp (limited to 'tests/test_dns.cpp') diff --git a/tests/test_dns.cpp b/tests/test_dns.cpp new file mode 100644 index 0000000..9a389bb --- /dev/null +++ b/tests/test_dns.cpp @@ -0,0 +1,82 @@ +#include + +#include + +#include "wireframe/l7/dns.hpp" + +using namespace wireframe::net; + +namespace { + +// "example.com" A query, id=0x129d - the same shape as the real query +// captured live over tailscale0 while testing the DNS dissector against +// tshark (id 0x129d / 4765 matched tshark's independent decode exactly). +std::vector example_com_query() { + return { + 0x12, 0x9d, // id = 4765 + 0x01, 0x00, // flags: RD=1 + 0x00, 0x01, // qdcount = 1 + 0x00, 0x00, // ancount = 0 + 0x00, 0x00, // nscount = 0 + 0x00, 0x00, // arcount = 0 + 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, + 0x00, 0x01, // qtype = A + 0x00, 0x01, // qclass = IN + }; +} + +} // namespace + +TEST_CASE("parse_dns decodes a query") { + auto msg = parse_dns(example_com_query()); + REQUIRE(msg.has_value()); + CHECK(msg->header.id == 4765); + CHECK_FALSE(msg->header.is_response); + CHECK(msg->header.qdcount == 1); + REQUIRE(msg->question.has_value()); + CHECK(msg->question->name == "example.com"); + CHECK(msg->question->qtype == 1); +} + +TEST_CASE("parse_dns decodes a response") { + std::vector bytes = { + 0x12, 0x9d, + 0x81, 0x80, // flags: QR=1 (response), RD=1, RA=1 + 0x00, 0x01, // qdcount = 1 + 0x00, 0x02, // ancount = 2 + 0x00, 0x00, + 0x00, 0x00, + 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, + 0x00, 0x01, 0x00, 0x01, + }; + auto msg = parse_dns(bytes); + REQUIRE(msg.has_value()); + CHECK(msg->header.is_response); + CHECK(msg->header.ancount == 2); +} + +TEST_CASE("parse_dns rejects a truncated header") { + std::vector bytes(5, 0); + CHECK_FALSE(parse_dns(bytes).has_value()); +} + +TEST_CASE("read_dns_name rejects a compression pointer") { + std::vector bytes = {0xC0, 0x0C}; // pointer: unsupported by design + CHECK_FALSE(read_dns_name(bytes, 0).has_value()); +} + +TEST_CASE("DnsDissector claims port 53 and its summary matches parse_dns") { + DnsDissector dissector; + CHECK(dissector.port() == kDnsPort); + + auto summary = dissector.summarize(example_com_query()); + REQUIRE(summary.has_value()); + CHECK(summary->substr(0, 9) == "DNS query"); + CHECK(summary->find("example.com") != std::string::npos); +} + +TEST_CASE("DnsDissector::summarize returns nullopt for a truncated payload") { + DnsDissector dissector; + std::vector bytes(5, 0); + CHECK_FALSE(dissector.summarize(bytes).has_value()); +} -- cgit v1.2.3