From f8fc8806401596b08779cf8c88da31408c9b0547 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Tue, 28 May 2024 01:55:00 +0200 Subject: Add ARP decoding and bring the TUI up to -c/-a parity ARP had zero treatment until now - its ethertype just fell through summarize_packet's "not IPv4/IPv6" branch, on traffic that appears on essentially every real LAN capture. Scoped to Ethernet/IPv4 addressing (the case that covers virtually all real ARP traffic), with tcpdump's own "who-has X tell Y" / "X is-at Y" phrasing rather than inventing new wording. Live-verified by flushing this machine's real gateway ARP entry and capturing the resulting request/reply on wlp1s0. TUI -c/-a were being parsed into RenderOptions but silently did nothing: run_tui()'s consumer thread had its own loop that never read them, unlike plain-text mode's render_packet(). Fixed to match, and caught a real bug while doing it - pushing up to two rows per packet (summary + reassembly line) against a single pop_front() would let the row deque grow past its cap under sustained -a activity; needed a while loop instead. Verified under tmux against the same split-segment HTTP scenario used to verify -a on the CLI and GUI. --- tests/test_arp.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/test_arp.cpp (limited to 'tests/test_arp.cpp') diff --git a/tests/test_arp.cpp b/tests/test_arp.cpp new file mode 100644 index 0000000..247782b --- /dev/null +++ b/tests/test_arp.cpp @@ -0,0 +1,89 @@ +#include + +#include + +#include "packeteer/net/arp.hpp" + +using namespace packeteer::net; + +namespace { + +std::vector arp_request() { + return { + 0x00, 0x01, // hardware type = Ethernet + 0x08, 0x00, // protocol type = IPv4 + 0x06, // hardware len = 6 + 0x04, // protocol len = 4 + 0x00, 0x01, // opcode = request + 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01, // sender MAC + 10, 0, 0, 1, // sender IP + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // target MAC (unknown, all zero) + 10, 0, 0, 2, // target IP + }; +} + +std::vector arp_reply() { + return { + 0x00, 0x01, + 0x08, 0x00, + 0x06, + 0x04, + 0x00, 0x02, // opcode = reply + 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x02, // sender MAC (the one who was asked) + 10, 0, 0, 2, // sender IP + 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01, // target MAC (the original requester) + 10, 0, 0, 1, // target IP + }; +} + +} // namespace + +TEST_CASE("parse_arp decodes a request with Ethernet/IPv4 addressing") { + auto arp = parse_arp(arp_request()); + REQUIRE(arp.has_value()); + CHECK(arp->header.opcode == kArpOpRequest); + REQUIRE(arp->sender_ip.has_value()); + REQUIRE(arp->sender_mac.has_value()); + REQUIRE(arp->target_ip.has_value()); + CHECK(arp->sender_ip->bytes == std::array{10, 0, 0, 1}); + CHECK(arp->target_ip->bytes == std::array{10, 0, 0, 2}); + CHECK(arp->sender_mac->bytes == std::array{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01}); +} + +TEST_CASE("parse_arp decodes a reply") { + auto arp = parse_arp(arp_reply()); + REQUIRE(arp.has_value()); + CHECK(arp->header.opcode == kArpOpReply); + REQUIRE(arp->sender_ip.has_value()); + CHECK(arp->sender_ip->bytes == std::array{10, 0, 0, 2}); +} + +TEST_CASE("parse_arp rejects a truncated header") { + std::vector bytes(5, 0); + CHECK_FALSE(parse_arp(bytes).has_value()); +} + +TEST_CASE("parse_arp decodes the header but skips addresses for non-Ethernet/IPv4") { + std::vector bytes = { + 0x00, 0x06, // hardware type = IEEE 802 (arbitrary, just not the common case) + 0x08, 0x00, + 0x08, // hardware len = 8, not 6 + 0x04, + 0x00, 0x01, + }; + auto arp = parse_arp(bytes); + REQUIRE(arp.has_value()); + CHECK(arp->header.hardware_len == 8); + CHECK_FALSE(arp->sender_ip.has_value()); + CHECK_FALSE(arp->sender_mac.has_value()); +} + +TEST_CASE("parse_arp treats a header claiming Ethernet/IPv4 but too short to hold it as header-only") { + std::vector bytes = { + 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, + 0xaa, 0xbb, 0xcc, // truncated sender MAC + }; + auto arp = parse_arp(bytes); + REQUIRE(arp.has_value()); + CHECK_FALSE(arp->sender_ip.has_value()); +} -- cgit v1.2.3