Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion libs/visor_dns/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ static std::unordered_map<uint16_t, std::string> RCodeNames({
{7, "YXRRSET"},
{8, "NXRRSET"},
{9, "NOTAUTH"},
{9, "NOTAUTH"},
{10, "NOTZONE"},
{11, "DSOTYPENI"},
{16, "BADVERS"},
Expand All @@ -228,4 +227,28 @@ static std::unordered_map<uint16_t, std::string> RCodeNames({
{23, "BADCOOKIE"},
});

static std::unordered_map<std::string, uint16_t> RCodeNumbers({
{"NOERROR", 0},
{"FORMERR", 1},
{"SRVFAIL", 2},
{"NXDOMAIN", 3},
{"NOTIMP", 4},
{"REFUSED", 5},
{"YXDOMAIN", 6},
{"YXRRSET", 7},
{"NXRRSET", 8},
{"NOTAUTH", 9},
{"NOTZONE", 10},
{"DSOTYPENI", 11},
{"BADVERS", 16},
{"BADSIG", 16},
{"BADKEY", 17},
{"BADTIME", 18},
{"BADMODE", 19},
{"BADNAME", 20},
{"BADALG", 21},
{"BADTRUNC", 22},
{"BADCOOKIE", 23},
});

}
53 changes: 44 additions & 9 deletions src/handlers/dns/v1/DnsStreamHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,47 @@ void DnsStreamHandler::start()
// Setup Filters
if (config_exists("exclude_noerror") && config_get<bool>("exclude_noerror")) {
_f_enabled.set(Filters::ExcludingRCode);
_f_rcode = NoError;
_f_rcodes.push_back(NoError);
} else if (config_exists("only_rcode")) {
std::vector<std::string> rcodes;
uint64_t want_code;
try {
want_code = config_get<uint64_t>("only_rcode");
} catch (const std::exception &e) {
throw ConfigException("DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer");
try {
rcodes = config_get<StringList>("only_rcode");
} catch (const std::exception &e) {
throw ConfigException("DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer or an array");
}
}
if (RCodeNames.find(want_code) != RCodeNames.end()) {
_f_enabled.set(Filters::OnlyRCode);
_f_rcode = want_code;
_f_enabled.set(Filters::OnlyRCode);
if (rcodes.empty()) {
if (RCodeNames.find(want_code) != RCodeNames.end()) {
_f_rcodes.push_back(static_cast<uint16_t>(want_code));
} else {
throw ConfigException("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode");
}
_register_predicate_filter(Filters::OnlyRCode, "only_rcode", std::to_string(want_code));
} else {
throw ConfigException("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode");
for (const auto &rcode : rcodes) {
if (std::all_of(rcode.begin(), rcode.end(), ::isdigit)) {
auto value = std::stoul(rcode);
if (RCodeNames.find(value) == RCodeNames.end()) {
throw ConfigException(fmt::format("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode: {}", value));
}
_f_rcodes.push_back(value);
} else {
std::string upper_rcode{rcode};
std::transform(upper_rcode.begin(), upper_rcode.end(), upper_rcode.begin(),
[](unsigned char c) { return std::toupper(c); });
if (RCodeNumbers.find(upper_rcode) != RCodeNumbers.end()) {
_f_rcodes.push_back(RCodeNumbers[upper_rcode]);
} else {
throw ConfigException(fmt::format("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode: {}", rcode));
}
}
}
}
_register_predicate_filter(Filters::OnlyRCode, "only_rcode", std::to_string(_f_rcode));
}
if (config_exists("only_queries") && config_get<bool>("only_queries")) {
_f_enabled.set(Filters::OnlyQueries);
Expand Down Expand Up @@ -430,8 +456,17 @@ inline void DnsStreamHandler::_register_predicate_filter(Filters filter, std::st
}
inline bool DnsStreamHandler::_filtering(DnsLayer &payload, [[maybe_unused]] PacketDirection dir, [[maybe_unused]] pcpp::ProtocolType l3, [[maybe_unused]] pcpp::ProtocolType l4, [[maybe_unused]] uint16_t port, timespec stamp)
{
if (_f_enabled[Filters::ExcludingRCode] && payload.getDnsHeader()->responseCode == _f_rcode) {
goto will_filter;
if (_f_enabled[Filters::ExcludingRCode]) {
auto rcode = payload.getDnsHeader()->responseCode;
if (std::any_of(_f_rcodes.begin(), _f_rcodes.end(), [rcode](uint16_t f_rcode) { return rcode == f_rcode; })) {
goto will_filter;
}
}
if (_f_enabled[Filters::OnlyRCode] && !_using_predicate_signals) {
auto rcode = payload.getDnsHeader()->responseCode;
if (std::none_of(_f_rcodes.begin(), _f_rcodes.end(), [rcode](uint16_t f_rcode) { return rcode == f_rcode; })) {
goto will_filter;
}
}
if (_f_enabled[Filters::AnswerCount] && payload.getAnswerCount() != _f_answer_count) {
goto will_filter;
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/dns/v1/DnsStreamHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class DnsStreamHandler final : public visor::StreamMetricsHandler<DnsMetricsMana
ConfigsMAX
};
std::bitset<Configs::ConfigsMAX> _c_enabled;
uint16_t _f_rcode{0};
std::vector<uint16_t> _f_rcodes;
uint64_t _f_answer_count{0};
std::vector<std::string> _f_qnames;
std::vector<uint16_t> _f_qtypes;
Expand Down
10 changes: 5 additions & 5 deletions src/handlers/dns/v1/tests/test_dns_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ TEST_CASE("DNS Filters: only_rcode nx", "[pcap][net]")
REQUIRE(j["wire_packets"]["filtered"] == 0);
}

TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
TEST_CASE("DNS Filters: only_rcode nx and refused", "[pcap][dns]")
{

PcapInputStream stream{"pcap-test"};
Expand All @@ -346,7 +346,7 @@ TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
c.config_set<uint64_t>("num_periods", 1);
DnsStreamHandler dns_handler{"dns-test", stream_proxy, &c};

dns_handler.config_set<uint64_t>("only_rcode", Refused);
dns_handler.config_set<visor::Configurable::StringList>("only_rcode", {"nxdomain", "5"});

dns_handler.start();
stream.start();
Expand All @@ -357,11 +357,11 @@ TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
REQUIRE(counters.RNOERROR.value() == 0);
REQUIRE(counters.SRVFAIL.value() == 0);
REQUIRE(counters.REFUSED.value() == 1);
REQUIRE(counters.NX.value() == 0);
REQUIRE(counters.NX.value() == 1);
REQUIRE(counters.NODATA.value() == 0);
nlohmann::json j;
dns_handler.metrics()->bucket(0)->to_json(j);
REQUIRE(j["wire_packets"]["filtered"] == 0);
REQUIRE(j["wire_packets"]["filtered"] == 22);
}
TEST_CASE("DNS Filters: only_qtypes AAAA and TXT", "[pcap][dns]")
{
Expand Down Expand Up @@ -829,7 +829,7 @@ TEST_CASE("DNS filter exceptions", "[pcap][dns][filter]")
SECTION("only_rcode as string")
{
dns_handler.config_set<std::string>("only_rcode", "1");
REQUIRE_THROWS_WITH(dns_handler.start(), "DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer");
REQUIRE_THROWS_WITH(dns_handler.start(), "DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer or an array");
}

SECTION("only_rcode invalid")
Expand Down
53 changes: 43 additions & 10 deletions src/handlers/dns/v2/DnsStreamHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,45 @@ void DnsStreamHandler::start()
// Setup Filters
if (config_exists("exclude_noerror") && config_get<bool>("exclude_noerror")) {
_f_enabled.set(Filters::ExcludingRCode);
_f_rcode = NoError;
_f_rcodes.push_back(NoError);
} else if (config_exists("only_rcode")) {
std::vector<std::string> rcodes;
uint64_t want_code;
try {
want_code = config_get<uint64_t>("only_rcode");
} catch (const std::exception &e) {
throw ConfigException("DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer");
try {
rcodes = config_get<StringList>("only_rcode");
} catch (const std::exception &e) {
throw ConfigException("DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer or an array");
}
}
if (RCodeNames.find(want_code) != RCodeNames.end()) {
_f_enabled.set(Filters::OnlyRCode);
_f_rcode = want_code;
_f_enabled.set(Filters::OnlyRCode);
if (rcodes.empty()) {
if (RCodeNames.find(want_code) != RCodeNames.end()) {
_f_rcodes.push_back(static_cast<uint16_t>(want_code));
} else {
throw ConfigException("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode");
}
} else {
throw ConfigException("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode");
for (const auto &rcode : rcodes) {
if (std::all_of(rcode.begin(), rcode.end(), ::isdigit)) {
auto value = std::stoul(rcode);
if (RCodeNames.find(value) == RCodeNames.end()) {
throw ConfigException(fmt::format("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode: {}", value));
}
_f_rcodes.push_back(value);
} else {
std::string upper_rcode{rcode};
std::transform(upper_rcode.begin(), upper_rcode.end(), upper_rcode.begin(),
[](unsigned char c) { return std::toupper(c); });
if (RCodeNumbers.find(upper_rcode) != RCodeNumbers.end()) {
_f_rcodes.push_back(RCodeNumbers[upper_rcode]);
} else {
throw ConfigException(fmt::format("DnsStreamHandler: only_rcode filter contained an invalid/unsupported rcode: {}", rcode));
}
}
}
}
}
if (config_exists("only_dnssec_response") && config_get<bool>("only_dnssec_response")) {
Expand Down Expand Up @@ -412,10 +438,17 @@ inline bool DnsStreamHandler::_filtering(DnsLayer &payload, PacketDirection dir,
if (_f_enabled[Filters::DisableOut] && dir == PacketDirection::toHost) {
goto will_filter;
}
if (_f_enabled[Filters::ExcludingRCode] && payload.getDnsHeader()->responseCode == _f_rcode) {
goto will_filter;
} else if (_f_enabled[Filters::OnlyRCode] && payload.getDnsHeader()->responseCode != _f_rcode) {
goto will_filter;
if (_f_enabled[Filters::ExcludingRCode]) {
auto rcode = payload.getDnsHeader()->responseCode;
if (std::any_of(_f_rcodes.begin(), _f_rcodes.end(), [rcode](uint16_t f_rcode) { return rcode == f_rcode; })) {
goto will_filter;
}
}
if (_f_enabled[Filters::OnlyRCode]) {
auto rcode = payload.getDnsHeader()->responseCode;
if (std::none_of(_f_rcodes.begin(), _f_rcodes.end(), [rcode](uint16_t f_rcode) { return rcode == f_rcode; })) {
goto will_filter;
}
}
if (_f_enabled[Filters::AnswerCount] && payload.getAnswerCount() != _f_answer_count) {
goto will_filter;
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/dns/v2/DnsStreamHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ class DnsStreamHandler final : public visor::StreamMetricsHandler<DnsMetricsMana
ConfigsMAX
};
std::bitset<Configs::ConfigsMAX> _c_enabled;
uint16_t _f_rcode{0};
std::vector<uint16_t> _f_rcodes;
uint64_t _f_answer_count{0};
std::vector<std::string> _f_qnames;
std::vector<uint16_t> _f_qtypes;
Expand Down
10 changes: 5 additions & 5 deletions src/handlers/dns/v2/tests/test_dns_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ TEST_CASE("DNS Filters: only_rcode nx", "[pcap][net]")
REQUIRE(j["filtered_packets"] == 19);
}

TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
TEST_CASE("DNS Filters: only_rcode refused and nx", "[pcap][dns]")
{

PcapInputStream stream{"pcap-test"};
Expand All @@ -345,7 +345,7 @@ TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
c.config_set<uint64_t>("num_periods", 1);
DnsStreamHandler dns_handler{"dns-test", stream_proxy, &c};

dns_handler.config_set<uint64_t>("only_rcode", Refused);
dns_handler.config_set<visor::Configurable::StringList>("only_rcode", {"nxdomain", "5"});

dns_handler.start();
stream.start();
Expand All @@ -356,11 +356,11 @@ TEST_CASE("DNS Filters: only_rcode refused", "[pcap][dns]")
REQUIRE(counters.RNOERROR.value() == 0);
REQUIRE(counters.SRVFAIL.value() == 0);
REQUIRE(counters.REFUSED.value() == 1);
REQUIRE(counters.NX.value() == 0);
REQUIRE(counters.NX.value() == 1);
REQUIRE(counters.NODATA.value() == 0);
nlohmann::json j;
dns_handler.metrics()->bucket(0)->to_json(j);
REQUIRE(j["filtered_packets"] == 19);
REQUIRE(j["filtered_packets"] == 17);
}
TEST_CASE("DNS Filters: only_qtypes AAAA and TXT", "[pcap][dns]")
{
Expand Down Expand Up @@ -773,7 +773,7 @@ TEST_CASE("DNS filter exceptions", "[pcap][dns][filter]")
SECTION("only_rcode as string")
{
dns_handler.config_set<std::string>("only_rcode", "1");
REQUIRE_THROWS_WITH(dns_handler.start(), "DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer");
REQUIRE_THROWS_WITH(dns_handler.start(), "DnsStreamHandler: wrong value type for only_rcode filter. It should be an integer or an array");
}

SECTION("only_rcode invalid")
Expand Down