From: Shibin K V (shikv) Date: Fri, 7 Nov 2025 12:26:07 +0000 (+0000) Subject: Pull request #4969: dns: add counters for different DNS flavors X-Git-Tag: 3.10.0.0~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43c9cda3afaabf8e011a3edf0b6bd2210066deba;p=thirdparty%2Fsnort3.git Pull request #4969: dns: add counters for different DNS flavors Merge in SNORT/snort3 from ~SHIKV/snort3:doh_counters to master Squashed commit of the following: commit a09815a683072f0a63125f114a7ba8ae639bbf2f Author: shibin k v Date: Mon Nov 3 01:58:24 2025 -0600 dns: add counters for different DNS flavors --- diff --git a/src/flow/stream_flow.h b/src/flow/stream_flow.h index 65af57f21..4617affcd 100644 --- a/src/flow/stream_flow.h +++ b/src/flow/stream_flow.h @@ -40,7 +40,7 @@ public: virtual void* get_hi_msg_section(const Flow*) { return nullptr; } virtual void set_hi_msg_section(Flow*, void*) { } - virtual AppId get_appid_from_stream(const Flow*) { return APP_ID_NONE; } + virtual AppId get_appid_from_stream(const Flow*) = 0; // Stream based flows should override this interface to return parent flow // when child flow is passed as input virtual Flow* get_stream_parent_flow(Flow* cflow) { return cflow; } diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_dns_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_dns_test.cc index 5427de3de..615004613 100644 --- a/src/network_inspectors/appid/detector_plugins/test/detector_dns_test.cc +++ b/src/network_inspectors/appid/detector_plugins/test/detector_dns_test.cc @@ -43,6 +43,10 @@ public: { stream_id = 0; } + AppId get_appid_from_stream(const Flow*) override + { + return APP_ID_QUIC; + } }; static QuicStreamIntf quic_stream_intf; @@ -65,7 +69,7 @@ int ServiceDetector::incompatible_data(AppIdSession&, const snort::Packet*, Appi return 0; } // Stubs for AppIdInspector -static ServiceDNSData dd; +static ServiceDNSData dns_data; static bool return_null_data = false; ServiceDNSDoQData* dns_doq_data = nullptr; AppIdConfig test_app_config; @@ -86,24 +90,27 @@ int AppIdDetector::data_add(AppIdSession&, AppIdFlowData* dns_data) AppIdFlowData* AppIdDetector::data_get(const AppIdSession&) { - return return_null_data ? nullptr : ⅆ + return return_null_data ? nullptr : &dns_data; } -int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; } +int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) +{ + return 1; +} TEST_GROUP(detector_dns_doq_tests) { - DnsTcpServiceDetector* test_detector = nullptr; + DnsTcpServiceDetector* const test_detector = nullptr; void setup() override { - test_detector = new DnsTcpServiceDetector(&test_discovery); + const_cast(test_detector) = new DnsTcpServiceDetector(&test_discovery); } void teardown() override { delete test_detector; - test_detector = nullptr; - dd.free_dns_cache(); + const_cast(test_detector) = nullptr; + dns_data.free_dns_cache(); } }; @@ -112,7 +119,7 @@ TEST(detector_dns_doq_tests, doq_validator_match_full_session) OdpContext test_odp_ctxt(test_app_config, nullptr); AppIdModule test_module; AppIdInspector test_inspector(test_module); - dd.state = DNS_STATE_QUERY; + dns_data.state = DNS_STATE_QUERY; AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); Flow* flow = new Flow; test_asd.flow = flow; @@ -132,12 +139,12 @@ TEST(detector_dns_doq_tests, doq_validator_match_full_session) AppidChangeBits change_bits; AppIdDiscoveryArgs args(dns_tcp_packet, sizeof(dns_tcp_packet), APP_ID_FROM_INITIATOR, test_asd, nullptr, change_bits); auto result = test_detector->validate_doq(args); - dd.free_dns_cache(); + dns_data.free_dns_cache(); CHECK_EQUAL(APPID_INPROCESS, result); // Now send a response packet - dd.state = DNS_STATE_RESPONSE; - dd.id = 13330; + dns_data.state = DNS_STATE_RESPONSE; + dns_data.id = 13330; uint8_t dns_tcp_response[] = { 0x00, 0x25, // TCP length (37 bytes) 0x12, 0x34, // id @@ -170,7 +177,7 @@ TEST(detector_dns_doq_tests, doq_validator_in_process_cached) OdpContext test_odp_ctxt(test_app_config, nullptr); AppIdModule test_module; AppIdInspector test_inspector(test_module); - dd.state = DNS_STATE_QUERY; + dns_data.state = DNS_STATE_QUERY; AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); Flow* flow = new Flow; test_asd.flow = flow; @@ -184,7 +191,7 @@ TEST(detector_dns_doq_tests, doq_validator_in_process_cached) AppidChangeBits change_bits; AppIdDiscoveryArgs args(dns_tcp_packet_1, sizeof(dns_tcp_packet_1), APP_ID_FROM_INITIATOR, test_asd, nullptr, change_bits); auto result = test_detector->validate_doq(args); - CHECK_EQUAL(6, dd.cached_len); + CHECK_EQUAL(6, dns_data.cached_len); CHECK_EQUAL(APPID_INPROCESS, result); uint8_t dns_tcp_packet_2[]= { @@ -207,7 +214,7 @@ TEST(detector_dns_doq_tests, doq_validator_not_compatible) OdpContext test_odp_ctxt(test_app_config, nullptr); AppIdModule test_module; AppIdInspector test_inspector(test_module); - dd.state = DNS_STATE_QUERY; + dns_data.state = DNS_STATE_QUERY; AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); Flow* flow = new Flow; test_asd.flow = flow; @@ -238,7 +245,7 @@ TEST(detector_dns_doq_tests, doq_validator_no_match) OdpContext test_odp_ctxt(test_app_config, nullptr); AppIdModule test_module; AppIdInspector test_inspector(test_module); - dd.state = DNS_STATE_QUERY; + dns_data.state = DNS_STATE_QUERY; AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); Flow* flow = new Flow; test_asd.flow = flow; @@ -267,7 +274,7 @@ TEST(detector_dns_doq_tests, doq_validator_stream_intf) OdpContext test_odp_ctxt(test_app_config, nullptr); AppIdModule test_module; AppIdInspector test_inspector(test_module); - dd.state = DNS_STATE_QUERY; + dns_data.state = DNS_STATE_QUERY; AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); Flow* flow = new Flow; test_asd.flow = flow; diff --git a/src/service_inspectors/dns/dns.cc b/src/service_inspectors/dns/dns.cc index c86e71521..9a3439edf 100644 --- a/src/service_inspectors/dns/dns.cc +++ b/src/service_inspectors/dns/dns.cc @@ -27,7 +27,9 @@ #include "dns.h" +#include "appid/application_ids.h" #include "detection/detection_engine.h" +#include "flow/stream_flow.h" #include "log/messages.h" #include "profiler/profiler.h" #include "pub_sub/dns_events.h" @@ -51,10 +53,17 @@ const PegInfo dns_peg_names[] = { CountType::SUM, "packets", "total packets processed" }, { CountType::SUM, "requests", "total dns requests" }, { CountType::SUM, "responses", "total dns responses" }, + { CountType::SUM, "dns_over_udp", "total dns packets over udp" }, + { CountType::SUM, "dns_over_tcp", "total dns packets over tcp" }, + { CountType::SUM, "dns_over_http1", "total dns packets over http/1.1" }, + { CountType::SUM, "dns_over_http2", "total dns packets over http/2" }, + { CountType::SUM, "dns_over_http3", "total dns packets over http/3" }, + { CountType::SUM, "dns_over_quic", "total dns packets over quic" }, { CountType::NOW, "concurrent_sessions", "total concurrent dns sessions" }, { CountType::MAX, "max_concurrent_sessions", "maximum concurrent dns sessions" }, { CountType::SUM, "aborted_sessions", "total dns sessions aborted" }, + { CountType::END, nullptr, nullptr } }; @@ -145,7 +154,7 @@ DNSData* get_dns_session_data(Packet* p, bool from_server, DNSData& udpSessionDa return &udpSessionData; } - fd = (DnsFlowData*)((p->flow)->get_flow_data(DnsFlowData::inspector_id)); + fd = static_cast((p->flow)->get_flow_data(DnsFlowData::inspector_id)); if (fd) { fd->session.dns_events.set_packet(p); @@ -393,7 +402,7 @@ static uint16_t ParseDNSName( if (!dnsSessionData->curr_txt.dns_name.empty()) dnsSessionData->curr_txt.dns_name += "."; - dnsSessionData->curr_txt.dns_name.append((const char*)data, bytes_required); + dnsSessionData->curr_txt.dns_name.append(reinterpret_cast(data), bytes_required); } data += bytes_required; @@ -630,7 +639,7 @@ static inline uint16_t get_udp_trans_id(Packet* p) static bool is_in_udp_flow(Packet* p, uint16_t trans_id) { bool found = false; - DnsUdpFlowData* udp_flow_data = (DnsUdpFlowData*)((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); + DnsUdpFlowData* udp_flow_data = static_cast((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); if (udp_flow_data) found = udp_flow_data->trans_ids.find(trans_id) != udp_flow_data->trans_ids.end(); return found; @@ -639,7 +648,7 @@ static bool is_in_udp_flow(Packet* p, uint16_t trans_id) // Add DNS transaction ID to the UDP packet's flow data object static void add_to_udp_flow(Packet* p, uint16_t trans_id) { - DnsUdpFlowData* udp_flow_data = (DnsUdpFlowData*)((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); + DnsUdpFlowData* udp_flow_data = static_cast((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); if (!udp_flow_data) { udp_flow_data = new DnsUdpFlowData(); @@ -649,16 +658,16 @@ static void add_to_udp_flow(Packet* p, uint16_t trans_id) } // Remove DNS transaction ID from the UDP packet's flow data object -static void rm_from_udp_flow(Packet* p, uint16_t trans_id) +static void rm_from_udp_flow(Packet* p, uint16_t trans_id, bool is_payload) { - DnsUdpFlowData* udp_flow_data = (DnsUdpFlowData*)((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); + DnsUdpFlowData* udp_flow_data = static_cast((p->flow)->get_flow_data(DnsUdpFlowData::inspector_id)); bool should_close = true; if (udp_flow_data) { udp_flow_data->trans_ids.erase(trans_id); should_close = udp_flow_data->trans_ids.empty(); } - if (should_close && !p->flow->is_proxied()) + if (should_close && !is_payload) { // Mark the UDP flow as "closed" only when all trans_ids are matched // and removed by DNS-reply packets, or if the flow data object is not found @@ -1144,7 +1153,7 @@ void Dns::show(const SnortConfig*) const config->show(); } -void Dns::snort_dns(Packet* p, bool udp) +void Dns::snort_dns(Packet* p, bool udp, bool is_payload) { // cppcheck-suppress unreadVariable Profile profile(dnsPerfStats); @@ -1184,6 +1193,37 @@ void Dns::snort_dns(Packet* p, bool udp) if (dnsSessionData->flags & DNS_FLAG_NOT_DNS) return; + if (is_payload) + { + if (p->flow->stream_intf) + { + AppId appid = p->flow->stream_intf->get_appid_from_stream(p->flow); + switch (appid) + { + case APP_ID_QUIC: + dnsstats.dns_over_quic++; + break; + case APP_ID_HTTP3: + dnsstats.dns_over_http3++; + break; + case APP_ID_HTTP2: + dnsstats.dns_over_http2++; + break; + default: + break; + } + } + else + dnsstats.dns_over_http1++; + } + else + { + if (udp) + dnsstats.dns_over_udp++; + else + dnsstats.dns_over_tcp++; + } + dnsSessionData->dns_config = config; if ( from_server ) { @@ -1218,7 +1258,7 @@ void Dns::snort_dns(Packet* p, bool udp) } if (udp) - rm_from_udp_flow(p, trans_id); + rm_from_udp_flow(p, trans_id, is_payload); } else { @@ -1234,7 +1274,7 @@ void Dns::eval(Packet* p) assert((p->is_udp() and p->dsize and p->data) or p->has_tcp_data() or p->has_udp_quic_data()); assert(p->flow); if (p->has_udp_quic_data()) // DNS over QUIC follows DNS over TCP - snort_dns(p, false); + snort_dns(p, false, true); else snort_dns(p, p->is_udp()); } @@ -1271,7 +1311,7 @@ static void dns_init() static Inspector* dns_ctor(Module* m) { - DnsModule* mod = (DnsModule*)m; + DnsModule* mod = static_cast(m); return new Dns(mod); } diff --git a/src/service_inspectors/dns/dns.h b/src/service_inspectors/dns/dns.h index 916a29c04..d0cb97415 100644 --- a/src/service_inspectors/dns/dns.h +++ b/src/service_inspectors/dns/dns.h @@ -312,7 +312,7 @@ public: bool supports_no_ips() const override { return true; } - void snort_dns(snort::Packet* p, bool udp); + void snort_dns(snort::Packet* p, bool udp, bool is_payload = false); const DnsConfig* get_config() const { return config; } diff --git a/src/service_inspectors/dns/dns_module.h b/src/service_inspectors/dns/dns_module.h index 9512a092d..1e5057d4f 100644 --- a/src/service_inspectors/dns/dns_module.h +++ b/src/service_inspectors/dns/dns_module.h @@ -46,6 +46,12 @@ struct DnsStats PegCount packets; PegCount requests; PegCount responses; + PegCount dns_over_udp; + PegCount dns_over_tcp; + PegCount dns_over_http1; + PegCount dns_over_http2; + PegCount dns_over_http3; + PegCount dns_over_quic; PegCount concurrent_sessions; PegCount max_concurrent_sessions; PegCount aborted_sessions; diff --git a/src/service_inspectors/dns/dns_payload_event_handler.cc b/src/service_inspectors/dns/dns_payload_event_handler.cc index 65e2c5871..3cc09eaec 100644 --- a/src/service_inspectors/dns/dns_payload_event_handler.cc +++ b/src/service_inspectors/dns/dns_payload_event_handler.cc @@ -57,7 +57,7 @@ void DnsPayloadEventHandler::handle(DataEvent& event, Flow* flow) } if (is_udp) - static_cast(inspector).snort_dns(p, true); + static_cast(inspector).snort_dns(p, true, true); p->data = old_data; p->dsize = old_dsize;