]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2606 in SNORT/snort3 from ~ARMANDAV/snort3:rna_service to master
authorMasud Hasan (mashasan) <mashasan@cisco.com>
Tue, 10 Nov 2020 14:06:04 +0000 (14:06 +0000)
committerMasud Hasan (mashasan) <mashasan@cisco.com>
Tue, 10 Nov 2020 14:06:04 +0000 (14:06 +0000)
Squashed commit of the following:

commit dd50d18bef501ad08df34b257bd7d84d3265921b
Author: Arun Mandava <armandav@cisco.com>
Date:   Thu Nov 5 21:53:49 2020 -0500

    rna: support change service event with null version and vendor

src/host_tracker/host_tracker.cc
src/host_tracker/host_tracker.h
src/network_inspectors/rna/rna_app_discovery.cc
src/network_inspectors/rna/rna_app_discovery.h
src/network_inspectors/rna/rna_pnd.cc

index 10ba176a9b161074b1b7223309b36e644ed5d0ac..97341db794cdfdd07f0a4b12f04755aa7566b85c 100644 (file)
@@ -465,12 +465,10 @@ bool HostTracker::add_payload(HostApplication& local_ha, Port port, IpProtocol p
     return false;
 }
 
-HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t lseen,
-    bool& is_new, AppId appid)
+HostApplication* HostTracker::find_and_add_service_no_lock(Port port, IpProtocol proto,
+    uint32_t lseen, bool& is_new, AppId appid, uint16_t max_services)
 {
     host_tracker_stats.service_finds++;
-    lock_guard<mutex> lck(host_tracker_lock);
-
     HostApplication *available = nullptr;
 
     for ( auto& s : services )
@@ -487,6 +485,8 @@ HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t l
                     s.visibility = true;
                     num_visible_services++;
                 }
+                else
+                    s.hits = 0;
             }
             else if ( s.last_seen == 0 )
             {
@@ -498,7 +498,7 @@ HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t l
 
             s.last_seen = lseen;
 
-            return s;
+            return &s;
         }
         else if ( !available and !s.visibility )
             available = &s;
@@ -517,11 +517,23 @@ HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t l
         available->inferred_appid = false;
         available->user[0] = '\0';
         available->visibility = true;
-        return *available;
+        return available;
     }
 
-    services.emplace_back(port, proto, appid, false, 1, lseen);
-    return services.back();
+    if ( max_services == 0 or num_visible_services < max_services ) 
+    {
+        services.emplace_back(port, proto, appid, false, 1, lseen);
+        return &services.back();
+    }
+    return nullptr;
+}
+
+HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t lseen,
+    bool& is_new, AppId appid)
+{
+    lock_guard<mutex> lck(host_tracker_lock);
+    HostApplication* ha = find_and_add_service_no_lock(port, proto, lseen, is_new, appid);
+    return *ha;
 }
 
 void HostTracker::update_service(const HostApplication& ha)
@@ -579,6 +591,9 @@ bool HostTracker::update_service_info(HostApplication& ha, const char* vendor,
             if ( s.visibility == false )
                 return false;
 
+            if ( !version and !vendor )
+                return true;
+
             HostApplicationInfo* available = nullptr;
             for ( auto& i : s.info )
             {
@@ -645,25 +660,24 @@ bool HostTracker::update_service_banner(Port port, IpProtocol proto)
     return false;
 }
 
-bool HostTracker::update_service_user(Port port, IpProtocol proto, const char* user)
+bool HostTracker::update_service_user(Port port, IpProtocol proto, const char* user,
+    uint32_t lseen, uint16_t max_services)
 {
     host_tracker_stats.service_finds++;
+    bool is_new = false;
     lock_guard<mutex> lck(host_tracker_lock);
-    for ( auto& s : services )
-    {
-        if ( s.port == port and s.proto == proto )
-        {
-            if ( s.visibility == false)
-                return false;
 
-            if ( user and strncmp(user, s.user, INFO_SIZE) )
-            {
-                strncpy(s.user, user, INFO_SIZE);
-                s.user[INFO_SIZE-1] = '\0';
-                return true;
-            }
-            return false;
-        }
+    // Appid notifies user events before service events, so use find or add service function.
+    HostApplication* ha = find_and_add_service_no_lock(port, proto, lseen, is_new, 0,
+        max_services);
+    if ( !ha or ha->visibility == false )
+        return false;
+
+    if ( user and strncmp(user, ha->user, INFO_SIZE) )
+    {
+        strncpy(ha->user, user, INFO_SIZE);
+        ha->user[INFO_SIZE-1] = '\0';
+        return true;
     }
     return false;
 }
index 98d0d03917df7a20765f457b971f70da8537295c..77a0ffb9b1f624a1cc50f05109cd7202931eac9d 100644 (file)
@@ -314,7 +314,8 @@ public:
     bool update_service_info(HostApplication&, const char* vendor, const char* version,
         uint16_t max_info);
     bool update_service_banner(Port, IpProtocol);
-    bool update_service_user(Port, IpProtocol, const char* username);
+    bool update_service_user(Port, IpProtocol, const char* username, uint32_t lseen,
+        uint16_t max_services);
     void remove_inferred_services();
 
     size_t get_client_count();
@@ -418,6 +419,9 @@ private:
     bool add_payload_no_lock(const AppId, HostApplication*, size_t);
     HostApplication* find_service_no_lock(Port, IpProtocol, AppId);
     void update_ha_no_lock(HostApplication& dst, HostApplication& src);
+    
+    HostApplication* find_and_add_service_no_lock(Port, IpProtocol, uint32_t lseen,
+        bool& is_new, AppId, uint16_t max_services = 0);
 
     // Hide / delete the constructor from the outside world. We don't want to
     // have zombie host trackers, i.e. host tracker objects that live outside
index 65e55ea5f73a7c65d910982e4049db378bfd9284..c50fe73fa43751f74d1ffae6dbe842a709e20b65 100644 (file)
@@ -63,6 +63,7 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
     const auto& appid_change_bits = appid_event->get_change_bitset();
     const auto& appid_session_api = appid_event->get_appid_session_api();
     AppId service = appid_session_api.get_service_app_id();
+    bool newservice = false;
 
     if ( appid_change_bits[APPID_SERVICE_BIT] or appid_change_bits[APPID_CLIENT_BIT] or
         appid_change_bits[APPID_PAYLOAD_BIT] )
@@ -72,12 +73,8 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
 
         if ( appid_change_bits[APPID_SERVICE_BIT] and service > APP_ID_NONE )
         {
-            if ( p->packet_flags & PKT_FROM_SERVER )
-                discover_service(p, proto, ht, (const struct in6_addr*) src_ip->get_ip6_ptr(),
-                    src_mac, conf, logger, p->flow->server_port, service);
-            else if ( p->packet_flags & PKT_FROM_CLIENT )
-                discover_service(p, proto, ht, (const struct in6_addr*) src_ip->get_ip6_ptr(),
-                    src_mac, conf, logger, p->flow->client_port, service);
+            newservice = discover_service(p, proto, ht, p->flow->server_ip, src_mac, conf, logger,
+                p->flow->server_port, service);
         }
 
         if ( appid_change_bits[APPID_CLIENT_BIT] and client > APP_ID_NONE
@@ -87,7 +84,7 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
             if ( p->packet_flags & PKT_FROM_SERVER )
             {
                 auto cht = host_cache.find(p->flow->client_ip);
-                if (cht)
+                if ( cht )
                     discover_client(p, cht, (const struct in6_addr*) &p->flow->client_ip,
                         layer::get_eth_layer(p)->ether_dst, conf, logger, version, client,
                         service);
@@ -111,8 +108,14 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
         const char* version;
         const AppIdServiceSubtype* subtype;
         appid_session_api.get_service_info(vendor, version, subtype);
-        update_service_info(p, proto, vendor, version, ht, src_ip, src_mac, logger, conf,
-            service);
+        update_service_info(p, proto, vendor, version, ht, p->flow->server_ip, src_mac, logger,
+            conf, service);
+    }
+    else if ( newservice and appid_change_bits[APPID_SERVICE_BIT]
+        and service > APP_ID_NONE )
+    {
+        update_service_info(p, proto, nullptr, nullptr, ht, p->flow->server_ip, src_mac, logger,
+            conf, service);
     }
 
     if ( conf->enable_banner_grab and p->is_from_server() and
@@ -131,7 +134,7 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
         const char* username = appid_session_api.get_user_info(service, login);
         if ( login and service > APP_ID_NONE and username and *username )
             discover_user(p, ht, (const struct in6_addr*) p->ptrs.ip_api.get_dst()->get_ip6_ptr(),
-                logger, username, service, proto);
+                logger, username, service, proto, conf);
     }
 
     if ( p->is_from_client() and ( appid_change_bits[APPID_HOST_BIT] or
@@ -158,27 +161,45 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
     }
 }
 
-void RnaAppDiscovery::discover_service(const Packet* p, IpProtocol proto, RnaTracker& rt,
-    const struct in6_addr* src_ip, const uint8_t* src_mac, RnaConfig* conf,
-    RnaLogger& logger, uint16_t port, AppId service)
+bool RnaAppDiscovery::discover_service(const Packet* p, IpProtocol proto, RnaTracker& rt,
+    const SfIp& ip, const uint8_t* mac, RnaConfig* conf, RnaLogger& logger, uint16_t port,
+    AppId service)
 {
-    if ( conf and conf->max_host_services and conf->max_host_services <= rt->get_service_count() )
-        return;
+    RnaTracker htp;
+    if ( p->is_from_client() )
+    {
+        htp = host_cache.find(ip);
+        if ( !htp )
+            return false;
+
+        if ( layer::get_eth_layer(p) )
+            mac = layer::get_eth_layer(p)->ether_dst;
+        else
+            mac = htp->get_last_seen_mac();
+    }
+    else
+        htp = rt;
+
+    if ( conf and conf->max_host_services and conf->max_host_services <= htp->get_service_count() )
+        return false;
 
     bool is_new = false;
 
     // Work on a local copy instead of reference as we release lock during event generations
-    auto ha = rt->add_service(port, proto, (uint32_t) packet_time(), is_new, service);
+    auto ha = htp->add_service(port, proto, (uint32_t) packet_time(), is_new, service);
     if ( is_new )
     {
         if ( proto == IpProtocol::TCP )
-            logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, &rt, src_ip, src_mac, &ha);
+            logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, &htp,
+                (const struct in6_addr*) ip.get_ip6_ptr(), mac, &ha);
         else
-            logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, &rt, src_ip, src_mac, &ha);
+            logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, &htp,
+                (const struct in6_addr*) ip.get_ip6_ptr(), mac, &ha);
 
         ha.hits = 0; // hit count is reset after logs are written
-        rt->update_service(ha);
+        htp->update_service(ha);
     }
+    return is_new;
 }
 
 void RnaAppDiscovery::discover_payload(const Packet* p, IpProtocol proto, RnaTracker& rt,
@@ -232,28 +253,40 @@ void RnaAppDiscovery::discover_payload(const Packet* p, IpProtocol proto, RnaTra
 }
 
 void RnaAppDiscovery::update_service_info(const Packet* p, IpProtocol proto, const char* vendor,
-    const char* version, RnaTracker& rt, const SfIp* ip, const uint8_t* src_mac, RnaLogger& logger,
+    const char* version, RnaTracker& rt, const SfIp& ip, const uint8_t* mac, RnaLogger& logger,
     RnaConfig* conf, AppId service)
 {
-    if ( !vendor and !version )
-        return;
+    RnaTracker htp;
+    if ( p->is_from_client() )
+    {
+        htp = host_cache.find(ip);
+        if ( !htp )
+            return;
+
+        if ( layer::get_eth_layer(p) )
+            mac = layer::get_eth_layer(p)->ether_dst;
+        else
+            mac = htp->get_last_seen_mac();
+    }
+    else
+        htp = rt;
 
     HostApplication ha(p->flow->server_port, proto, service, false);
-    if ( !rt->update_service_info(ha, vendor, version, conf->max_host_service_info) )
+    if ( !htp->update_service_info(ha, vendor, version, conf->max_host_service_info) )
         return;
 
     // Work on a local copy for eventing purpose
     ha.last_seen = (uint32_t) packet_time();
 
     if ( proto == IpProtocol::TCP )
-        logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, &rt,
-            (const struct in6_addr*) ip->get_ip6_ptr(), src_mac, &ha);
+        logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, &htp,
+            (const struct in6_addr*) ip.get_ip6_ptr(), mac, &ha);
     else
-        logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, &rt,
-            (const struct in6_addr*) ip->get_ip6_ptr(), src_mac, &ha);
+        logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, &htp,
+            (const struct in6_addr*) ip.get_ip6_ptr(), mac, &ha);
 
     ha.hits = 0;
-    rt->update_service(ha);
+    htp->update_service(ha);
 }
 
 void RnaAppDiscovery::discover_banner(const Packet* p, IpProtocol proto, RnaTracker& rt,
@@ -285,9 +318,10 @@ void RnaAppDiscovery::discover_client(const Packet* p, RnaTracker& rt,
 
 void RnaAppDiscovery::discover_user(const Packet* p, RnaTracker& rt,
     const struct in6_addr* ip, RnaLogger& logger, const char* username,
-    AppId service, IpProtocol proto)
+    AppId service, IpProtocol proto, RnaConfig* conf)
 {
-    if ( rt->update_service_user(p->flow->server_port, proto, username) )
+    if ( rt->update_service_user(p->flow->server_port, proto, username,
+        (uint32_t) packet_time(), conf ? conf->max_host_services : 0) )
     {
         logger.log(RUA_EVENT, CHANGE_USER_LOGIN, p, &rt, ip, username,
             service, (uint32_t) packet_time());
index 1a9856b758ae55262c9b2f41149b8ba6966afb0c..dbbefac35f9a3d8b4d7dc48c4103083be09e6c8c 100644 (file)
@@ -27,8 +27,8 @@ class RnaAppDiscovery
 public:
     static void process(AppidEvent*, DiscoveryFilter&, RnaConfig*, RnaLogger&);
 
-    static void discover_service(const snort::Packet*, IpProtocol, RnaTracker&,
-        const struct in6_addr*, const uint8_t*, RnaConfig*, RnaLogger&, uint16_t port,
+    static bool discover_service(const snort::Packet*, IpProtocol, RnaTracker&,
+        const snort::SfIp&, const uint8_t*, RnaConfig*, RnaLogger&, uint16_t port,
         AppId service = APP_ID_NONE);
 
     static void discover_payload(const snort::Packet*, IpProtocol, RnaTracker&,
@@ -41,13 +41,13 @@ public:
         RnaLogger&, const char*, AppId client, AppId service);
 
     static void discover_user(const snort::Packet*, RnaTracker&, const struct in6_addr*,
-        RnaLogger&, const char* username, AppId, IpProtocol);
+        RnaLogger&, const char* username, AppId, IpProtocol, RnaConfig*);
 
     static void discover_banner(const snort::Packet*, IpProtocol, RnaTracker&,
         const snort::SfIp*, const uint8_t* mac, RnaLogger&, AppId);
 private:
     static void update_service_info(const snort::Packet*, IpProtocol, const char* vendor,
-        const char* version, RnaTracker&, const snort::SfIp*, const uint8_t*,
+        const char* version, RnaTracker&, const snort::SfIp&, const uint8_t*,
         RnaLogger&, RnaConfig*, AppId service);
 
     static void analyze_user_agent_fingerprint(const snort::Packet*, const char* host,
index 7b6510eb2e4d9e8947260f3633b026ec6645000c..020ccef1a14e2cfb912dcceeaac4fba58cfb0a28 100644 (file)
@@ -196,14 +196,6 @@ void RnaPnd::discover_network(const Packet* p, uint8_t ttl)
         logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
             packet_time());
 
-    if ( p->flow->two_way_traffic() )
-    {
-        auto proto = p->get_ip_proto_next();
-        if ( proto == IpProtocol::TCP or proto == IpProtocol::UDP )
-            RnaAppDiscovery::discover_service(p, proto, ht, src_ip_ptr, src_mac, conf,
-                logger, p->flow->server_port);
-    }
-
     if ( !new_host )
         generate_change_host_update(&ht, p, src_ip, src_mac, packet_time());