srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_dns.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_dns.cpp')
-rw-r--r--tests/test_dns.cpp82
1 files changed, 82 insertions, 0 deletions
diff --git a/tests/test_dns.cpp b/tests/test_dns.cpp
new file mode 100644
index 0000000..9a389bb
--- /dev/null
+++ b/tests/test_dns.cpp
@@ -0,0 +1,82 @@
+#include <doctest/doctest.h>
+
+#include <vector>
+
+#include "wireframe/l7/dns.hpp"
+
+using namespace wireframe::net;
+
+namespace {
+
+// "example.com" A query, id=0x129d - the same shape as the real query
+// captured live over tailscale0 while testing the DNS dissector against
+// tshark (id 0x129d / 4765 matched tshark's independent decode exactly).
+std::vector<unsigned char> example_com_query() {
+ return {
+ 0x12, 0x9d, // id = 4765
+ 0x01, 0x00, // flags: RD=1
+ 0x00, 0x01, // qdcount = 1
+ 0x00, 0x00, // ancount = 0
+ 0x00, 0x00, // nscount = 0
+ 0x00, 0x00, // arcount = 0
+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
+ 0x00, 0x01, // qtype = A
+ 0x00, 0x01, // qclass = IN
+ };
+}
+
+} // namespace
+
+TEST_CASE("parse_dns decodes a query") {
+ auto msg = parse_dns(example_com_query());
+ REQUIRE(msg.has_value());
+ CHECK(msg->header.id == 4765);
+ CHECK_FALSE(msg->header.is_response);
+ CHECK(msg->header.qdcount == 1);
+ REQUIRE(msg->question.has_value());
+ CHECK(msg->question->name == "example.com");
+ CHECK(msg->question->qtype == 1);
+}
+
+TEST_CASE("parse_dns decodes a response") {
+ std::vector<unsigned char> bytes = {
+ 0x12, 0x9d,
+ 0x81, 0x80, // flags: QR=1 (response), RD=1, RA=1
+ 0x00, 0x01, // qdcount = 1
+ 0x00, 0x02, // ancount = 2
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
+ 0x00, 0x01, 0x00, 0x01,
+ };
+ auto msg = parse_dns(bytes);
+ REQUIRE(msg.has_value());
+ CHECK(msg->header.is_response);
+ CHECK(msg->header.ancount == 2);
+}
+
+TEST_CASE("parse_dns rejects a truncated header") {
+ std::vector<unsigned char> bytes(5, 0);
+ CHECK_FALSE(parse_dns(bytes).has_value());
+}
+
+TEST_CASE("read_dns_name rejects a compression pointer") {
+ std::vector<unsigned char> bytes = {0xC0, 0x0C}; // pointer: unsupported by design
+ CHECK_FALSE(read_dns_name(bytes, 0).has_value());
+}
+
+TEST_CASE("DnsDissector claims port 53 and its summary matches parse_dns") {
+ DnsDissector dissector;
+ CHECK(dissector.port() == kDnsPort);
+
+ auto summary = dissector.summarize(example_com_query());
+ REQUIRE(summary.has_value());
+ CHECK(summary->substr(0, 9) == "DNS query");
+ CHECK(summary->find("example.com") != std::string::npos);
+}
+
+TEST_CASE("DnsDissector::summarize returns nullopt for a truncated payload") {
+ DnsDissector dissector;
+ std::vector<unsigned char> bytes(5, 0);
+ CHECK_FALSE(dissector.summarize(bytes).has_value());
+}