]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4649: appid: Caching for tcp dns packets.
authorVitalii Izhyk -X (viizhyk - SOFTSERVE INC at Cisco) <viizhyk@cisco.com>
Mon, 7 Apr 2025 19:19:29 +0000 (19:19 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Mon, 7 Apr 2025 19:19:29 +0000 (19:19 +0000)
Merge in SNORT/snort3 from ~VIIZHYK/snort3:dns_caching_appid to master

Squashed commit of the following:

commit 2845f901f9c45b7e284f84378f3cae66ed677ba3
Author: viizhyk <viizhyk@cisco.com>
Date:   Wed Apr 2 14:16:49 2025 -0400

    appid: Added caching for dns detector.

src/network_inspectors/appid/detector_plugins/detector_dns.cc

index f35d4a125c87bac4caf5308d4e1c61b978e600a2..f5b55f8cb15c1d80da331847403eb5b3be1be1b1 100644 (file)
@@ -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<ServiceDNSData*>(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<uint8_t*>(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<ServiceDNSData*>(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;