#include #include "packeteer/l7/dissector.hpp" using namespace packeteer::net; namespace { // A dissector that claims a port but never actually matches any // payload - stands in for e.g. TlsSniDissector receiving QUIC bytes // on port 443: same port, wrong protocol, never succeeds. class NeverMatchesDissector : public L7Dissector { public: explicit NeverMatchesDissector(std::uint16_t port) : port_(port) {} std::uint16_t port() const override { return port_; } std::optional summarize(std::span) const override { return std::nullopt; } private: std::uint16_t port_; }; class AlwaysMatchesDissector : public L7Dissector { public: AlwaysMatchesDissector(std::uint16_t port, std::string label) : port_(port), label_(std::move(label)) {} std::uint16_t port() const override { return port_; } std::optional summarize(std::span) const override { return label_; } private: std::uint16_t port_; std::string label_; }; } // namespace TEST_CASE("L7Registry falls through to a later dissector on the same port " "when an earlier one fails to match") { NeverMatchesDissector tls_like(443); AlwaysMatchesDissector quic_like(443, "QUIC something"); L7Registry registry; registry.add(&tls_like); registry.add(&quic_like); auto result = registry.dissect(443, {}); REQUIRE(result.has_value()); CHECK(*result == "QUIC something"); } TEST_CASE("L7Registry still returns the first dissector to succeed, not the last") { AlwaysMatchesDissector first(80, "first"); AlwaysMatchesDissector second(80, "second"); L7Registry registry; registry.add(&first); registry.add(&second); auto result = registry.dissect(80, {}); REQUIRE(result.has_value()); CHECK(*result == "first"); } TEST_CASE("L7Registry returns nullopt when no dissector on the port matches") { NeverMatchesDissector only(443); L7Registry registry; registry.add(&only); CHECK_FALSE(registry.dissect(443, {}).has_value()); }