From: Vitalii Izhyk -X (viizhyk - SOFTSERVE INC at Cisco) Date: Mon, 7 Apr 2025 19:19:29 +0000 (+0000) Subject: Pull request #4649: appid: Caching for tcp dns packets. X-Git-Tag: 3.7.3.0~4 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=cf1095e3a7fca414c67671a6e82fd5a755dd7b24;p=thirdparty%2Fsnort3.git Pull request #4649: appid: Caching for tcp dns packets. Merge in SNORT/snort3 from ~VIIZHYK/snort3:dns_caching_appid to master Squashed commit of the following: commit 2845f901f9c45b7e284f84378f3cae66ed677ba3 Author: viizhyk Date: Wed Apr 2 14:16:49 2025 -0400 appid: Added caching for dns detector. --- diff --git a/src/network_inspectors/appid/detector_plugins/detector_dns.cc b/src/network_inspectors/appid/detector_plugins/detector_dns.cc index f35d4a125..f5b55f8cb 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_dns.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_dns.cc @@ -137,12 +137,53 @@ enum DNSState class ServiceDNSData : public AppIdFlowData { public: - ~ServiceDNSData() override = default; + ServiceDNSData(); + ~ServiceDNSData() override; + void save_dns_cache(uint16_t size, const uint8_t* data); + void free_dns_cache(); DNSState state = DNS_STATE_QUERY; + uint8_t* cached_data = nullptr; + uint16_t cached_len = 0; uint16_t id = 0; }; +void ServiceDNSData::save_dns_cache(uint16_t size, const uint8_t* data) +{ + if(size > 0) + { + cached_data = (uint8_t*)snort_calloc(size, sizeof(uint8_t)); + if(cached_data) + { + memcpy(cached_data, data, size); + } + cached_len = size; + } +} + +void ServiceDNSData::free_dns_cache() +{ + if(cached_data) + { + snort_free(cached_data); + cached_data = nullptr; + } + + cached_len = 0; +} + +ServiceDNSData::ServiceDNSData() +{ + state = DNS_STATE_QUERY; + cached_data = nullptr; + cached_len = 0; +} + +ServiceDNSData::~ServiceDNSData() +{ + free_dns_cache(); +} + DnsTcpServiceDetector::DnsTcpServiceDetector(ServiceDiscovery* sd) { handler = sd; @@ -621,10 +662,15 @@ inprocess: int DnsTcpServiceDetector::validate(AppIdDiscoveryArgs& args) { int rval; + uint8_t* reallocated_data = nullptr; + const uint8_t* data = args.data; + uint16_t size = args.size; + ServiceDNSData* dd = static_cast(data_get(args.asd)); { if (!args.size) goto inprocess; + if (args.size < sizeof(DNSTCPHeader)) { if (args.dir == APP_ID_FROM_INITIATOR) @@ -632,13 +678,35 @@ int DnsTcpServiceDetector::validate(AppIdDiscoveryArgs& args) else goto fail; } - const DNSTCPHeader* hdr = (const DNSTCPHeader*)args.data; - const uint8_t* data = args.data + sizeof(DNSTCPHeader); - uint16_t size = args.size - sizeof(DNSTCPHeader); + + if (!dd) + { + dd = new ServiceDNSData; + data_add(args.asd, dd); + } + + if (dd->cached_data and dd->cached_len and args.dir == APP_ID_FROM_INITIATOR) + { + reallocated_data = static_cast(snort_calloc(dd->cached_len + args.size, sizeof(uint8_t))); + memcpy(reallocated_data, dd->cached_data, dd->cached_len); + memcpy(reallocated_data + dd->cached_len, args.data, args.size); + size = dd->cached_len + args.size; + dd->free_dns_cache(); + data = reallocated_data; + } + + const DNSTCPHeader* hdr = (const DNSTCPHeader*)data; + data = data + sizeof(DNSTCPHeader); + size = size - sizeof(DNSTCPHeader); uint16_t tmp = ntohs(hdr->length); - if (tmp > size) + if (tmp > size and args.dir == APP_ID_FROM_INITIATOR) + { + dd->save_dns_cache(args.size, args.data); + goto inprocess; + } else if (tmp > size and args.dir == APP_ID_FROM_RESPONDER) { goto not_compatible; + } if (tmp < sizeof(DNSHeader) || dns_validate_header(args.dir, (const DNSHeader*)data, args.asd.get_odp_ctxt().dns_host_reporting, args.asd)) @@ -656,13 +724,6 @@ int DnsTcpServiceDetector::validate(AppIdDiscoveryArgs& args) if (rval != APPID_SUCCESS) goto tcp_done; - ServiceDNSData* dd = static_cast(data_get(args.asd)); - if (!dd) - { - dd = new ServiceDNSData; - data_add(args.asd, dd); - } - if (dd->state == DNS_STATE_QUERY) { if (args.dir != APP_ID_FROM_INITIATOR) @@ -689,22 +750,31 @@ tcp_done: case APPID_INPROCESS: goto inprocess; default: + dd->free_dns_cache(); return rval; } success: + if (reallocated_data) + snort_free(reallocated_data); args.asd.set_session_flags(APPID_SESSION_CONTINUE); return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DNS); not_compatible: + if (reallocated_data) + snort_free(reallocated_data); incompatible_data(args.asd, args.pkt, args.dir); return APPID_NOT_COMPATIBLE; fail: + if (reallocated_data) + snort_free(reallocated_data); fail_service(args.asd, args.pkt, args.dir); return APPID_NOMATCH; inprocess: + if (reallocated_data) + snort_free(reallocated_data); add_app(args.asd, APP_ID_NONE, APP_ID_DNS, nullptr, args.change_bits); service_inprocess(args.asd, args.pkt, args.dir); return APPID_INPROCESS;