diff options
Diffstat (limited to 'tests/test_quic.cpp')
| -rw-r--r-- | tests/test_quic.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/tests/test_quic.cpp b/tests/test_quic.cpp new file mode 100644 index 0000000..2366176 --- /dev/null +++ b/tests/test_quic.cpp @@ -0,0 +1,97 @@ +#include <doctest/doctest.h> + +#include <vector> + +#include "packeteer/l7/quic.hpp" + +using namespace packeteer::net; + +namespace { + +std::vector<unsigned char> long_header(std::uint8_t type_bits, std::uint32_t version, + std::vector<unsigned char> dcid, + std::vector<unsigned char> scid) { + std::vector<unsigned char> bytes; + bytes.push_back(static_cast<unsigned char>(0xC0 | (type_bits << 4))); // long form, fixed bit + bytes.push_back(static_cast<unsigned char>(version >> 24)); + bytes.push_back(static_cast<unsigned char>(version >> 16)); + bytes.push_back(static_cast<unsigned char>(version >> 8)); + bytes.push_back(static_cast<unsigned char>(version)); + bytes.push_back(static_cast<unsigned char>(dcid.size())); + bytes.insert(bytes.end(), dcid.begin(), dcid.end()); + bytes.push_back(static_cast<unsigned char>(scid.size())); + bytes.insert(bytes.end(), scid.begin(), scid.end()); + return bytes; +} + +} // namespace + +TEST_CASE("parse_quic decodes a long-header Initial packet's version and connection IDs") { + auto bytes = long_header(0x00, 0x00000001, {0xAA, 0xBB, 0xCC, 0xDD}, {0x11, 0x22}); + auto pkt = parse_quic(bytes); + REQUIRE(pkt.has_value()); + CHECK(pkt->is_long_header); + REQUIRE(pkt->long_header.has_value()); + CHECK(pkt->long_header->type == QuicLongPacketType::kInitial); + CHECK(pkt->long_header->version == 0x00000001); + CHECK(pkt->long_header->dcid == std::vector<unsigned char>{0xAA, 0xBB, 0xCC, 0xDD}); + CHECK(pkt->long_header->scid == std::vector<unsigned char>{0x11, 0x22}); +} + +TEST_CASE("parse_quic decodes each long-packet type from its type bits") { + CHECK(parse_quic(long_header(0x00, 1, {}, {}))->long_header->type == + QuicLongPacketType::kInitial); + CHECK(parse_quic(long_header(0x01, 1, {}, {}))->long_header->type == + QuicLongPacketType::kZeroRtt); + CHECK(parse_quic(long_header(0x02, 1, {}, {}))->long_header->type == + QuicLongPacketType::kHandshake); + CHECK(parse_quic(long_header(0x03, 1, {}, {}))->long_header->type == + QuicLongPacketType::kRetry); +} + +TEST_CASE("parse_quic treats version 0 as Version Negotiation regardless of type bits") { + auto pkt = parse_quic(long_header(0x02, 0x00000000, {0xAA}, {})); + REQUIRE(pkt.has_value()); + CHECK(pkt->long_header->type == QuicLongPacketType::kVersionNegotiation); +} + +TEST_CASE("parse_quic recognizes a short-header packet without decoding past the first byte") { + std::vector<unsigned char> bytes = {0x40, 0xAA, 0xBB, 0xCC}; // short form, fixed bit set + auto pkt = parse_quic(bytes); + REQUIRE(pkt.has_value()); + CHECK_FALSE(pkt->is_long_header); + CHECK_FALSE(pkt->long_header.has_value()); +} + +TEST_CASE("parse_quic rejects a packet with the Fixed Bit clear") { + std::vector<unsigned char> bytes = {0x00, 0xAA, 0xBB, 0xCC}; + CHECK_FALSE(parse_quic(bytes).has_value()); +} + +TEST_CASE("parse_quic rejects a long-header packet truncated before the version field") { + std::vector<unsigned char> bytes = {0xC0, 0x00, 0x00}; + CHECK_FALSE(parse_quic(bytes).has_value()); +} + +TEST_CASE("parse_quic rejects a long-header packet whose DCID length exceeds the buffer") { + std::vector<unsigned char> bytes = {0xC0, 0x00, 0x00, 0x00, 0x01, 20}; // claims 20-byte DCID + CHECK_FALSE(parse_quic(bytes).has_value()); +} + +TEST_CASE("QuicDissector claims port 443 and formats an Initial packet") { + QuicDissector dissector; + CHECK(dissector.port() == kQuicPort); + + auto bytes = long_header(0x00, 0x00000001, {0xAA, 0xBB}, {}); + auto summary = dissector.summarize(bytes); + REQUIRE(summary.has_value()); + CHECK(*summary == "QUIC Initial v=0x00000001 dcid=aabb"); +} + +TEST_CASE("QuicDissector formats a short-header packet distinctly, without a fake dcid") { + QuicDissector dissector; + std::vector<unsigned char> bytes = {0x40, 0xAA, 0xBB, 0xCC}; + auto summary = dissector.summarize(bytes); + REQUIRE(summary.has_value()); + CHECK(*summary == "QUIC 1-RTT (short header)"); +} |