From 9046e6a10fd2d987cf6f6dc601ed3a75d286793f Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:59:00 +0200 Subject: Unwrap VLAN (802.1Q/802.1ad) tags before protocol dispatch The single highest-value coverage gap so far, and structural rather than a new dissector: a VLAN-tagged frame's ethertype reads as 0x8100, so every existing decoder - ARP, IPv4, IPv6, and everything built on top of them - was completely invisible on any tagged network. walk_vlan_tags() (ethernet.hpp) is composable and separate from parse_ethernet(), the same relationship walk_ipv6_extension_headers() has to parse_ipv6(): the base parse stays an unconditional fixed-header decode, and this is what a caller reaches for when it needs the real protocol underneath. Handles stacked (QinQ) tags, bounded at 4 levels against a corrupt/hostile frame claiming an unbounded chain. Live-verified with genuine kernel-tagged frames, not synthetic bytes: a dummy0 interface with an 802.1Q dummy0.42 sub-interface (VLAN 42), captured on the parent while pinging out the sub-interface. Both interfaces and the kernel modules they pulled in were torn down afterward. --- tests/test_summarize.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests/test_summarize.cpp') diff --git a/tests/test_summarize.cpp b/tests/test_summarize.cpp index 27e0dd3..d7b223a 100644 --- a/tests/test_summarize.cpp +++ b/tests/test_summarize.cpp @@ -186,6 +186,22 @@ TEST_CASE("summarize_packet decodes an ARP request end to end") { "ARP who-has 10.0.0.2 tell 10.0.0.1 (aa:bb:cc:dd:ee:ff)"); } +TEST_CASE("summarize_packet unwraps a VLAN tag to reach the real ARP payload underneath") { + std::vector bytes = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x81, 0x00, // ethertype: 802.1Q + 0x00, 42, // TCI: VLAN 42 + 0x08, 0x06, // real ethertype: ARP + 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 10, 0, 0, 1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 10, 0, 0, 2, + }; + auto line = packeteer::summarize_packet(bytes, DLT_EN10MB); + CHECK(line == + "ETH aa:bb:cc:dd:ee:ff -> 11:22:33:44:55:66 ethertype=0x8100 vlan=42 | " + "ARP who-has 10.0.0.2 tell 10.0.0.1 (aa:bb:cc:dd:ee:ff)"); +} + TEST_CASE("hex_dump_lines produces one line per 16 bytes, with the right byte count") { std::vector bytes(20, 0); for (std::size_t i = 0; i < bytes.size(); ++i) bytes[i] = static_cast(i); -- cgit v1.2.3