srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_net.cpp')
-rw-r--r--tests/test_net.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/tests/test_net.cpp b/tests/test_net.cpp
index 19667da..2702758 100644
--- a/tests/test_net.cpp
+++ b/tests/test_net.cpp
@@ -30,6 +30,63 @@ TEST_CASE("parse_ethernet rejects a frame shorter than the header") {
CHECK_FALSE(parse_ethernet(bytes).has_value());
}
+TEST_CASE("walk_vlan_tags passes an untagged ethertype through unchanged") {
+ std::vector<unsigned char> payload = {0xDE, 0xAD, 0xBE, 0xEF};
+ auto result = walk_vlan_tags(kEthertypeIPv4, payload);
+ CHECK(result.vlan_ids.empty());
+ CHECK(result.ethertype == kEthertypeIPv4);
+ REQUIRE(result.payload.size() == 4);
+ CHECK(result.payload[0] == 0xDE);
+}
+
+TEST_CASE("walk_vlan_tags unwraps a single 802.1Q tag") {
+ std::vector<unsigned char> payload = {
+ 0x00, 42, // TCI: VLAN ID 42 (PCP/DEI bits left zero)
+ 0x08, 0x00, // real ethertype: IPv4
+ 0xDE, 0xAD, // real payload
+ };
+ auto result = walk_vlan_tags(kEthertypeVlan, payload);
+ REQUIRE(result.vlan_ids.size() == 1);
+ CHECK(result.vlan_ids[0] == 42);
+ CHECK(result.ethertype == kEthertypeIPv4);
+ REQUIRE(result.payload.size() == 2);
+ CHECK(result.payload[0] == 0xDE);
+}
+
+TEST_CASE("walk_vlan_tags unwraps a stacked QinQ pair, outer to inner") {
+ std::vector<unsigned char> payload = {
+ 0x00, 100, // outer TCI: VLAN 100
+ 0x81, 0x00, // inner tag's TPID
+ 0x00, 42, // inner TCI: VLAN 42
+ 0x08, 0x00, // real ethertype: IPv4
+ 0xBE, 0xEF,
+ };
+ auto result = walk_vlan_tags(kEthertypeVlanQinQ, payload);
+ REQUIRE(result.vlan_ids.size() == 2);
+ CHECK(result.vlan_ids[0] == 100);
+ CHECK(result.vlan_ids[1] == 42);
+ CHECK(result.ethertype == kEthertypeIPv4);
+}
+
+TEST_CASE("walk_vlan_tags stops at a truncated tag rather than reading past it") {
+ std::vector<unsigned char> payload = {0x00, 42}; // 2 bytes: not a full 4-byte tag
+ auto result = walk_vlan_tags(kEthertypeVlan, payload);
+ CHECK(result.vlan_ids.empty());
+ CHECK(result.ethertype == kEthertypeVlan); // unchanged: nothing was actually unwrapped
+}
+
+TEST_CASE("walk_vlan_tags is bounded against a claimed unbounded tag chain") {
+ // Each 4-byte block claims "the next ethertype is another VLAN
+ // tag" - a corrupt/hostile frame that never actually reaches a
+ // real ethertype. Must stop, not loop indefinitely.
+ std::vector<unsigned char> payload;
+ for (int i = 0; i < 100; ++i) {
+ payload.insert(payload.end(), {0x00, 0x01, 0x81, 0x00});
+ }
+ auto result = walk_vlan_tags(kEthertypeVlan, payload);
+ CHECK(result.vlan_ids.size() <= 4);
+}
+
TEST_CASE("parse_ipv4 decodes header fields and leaves the right payload") {
std::vector<unsigned char> bytes(20, 0);
bytes[0] = 0x45; // version 4, IHL 5 (20-byte header, no options)