From: Masud Hasan (mashasan) Date: Tue, 10 Nov 2020 14:06:04 +0000 (+0000) Subject: Merge pull request #2606 in SNORT/snort3 from ~ARMANDAV/snort3:rna_service to master X-Git-Tag: 3.0.3-5~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f347e541ab27dfb94d1468d6392ef40627c87b6;p=thirdparty%2Fsnort3.git Merge pull request #2606 in SNORT/snort3 from ~ARMANDAV/snort3:rna_service to master Squashed commit of the following: commit dd50d18bef501ad08df34b257bd7d84d3265921b Author: Arun Mandava Date: Thu Nov 5 21:53:49 2020 -0500 rna: support change service event with null version and vendor --- diff --git a/src/host_tracker/host_tracker.cc b/src/host_tracker/host_tracker.cc index 10ba176a9..97341db79 100644 --- a/src/host_tracker/host_tracker.cc +++ b/src/host_tracker/host_tracker.cc @@ -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 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 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 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; } diff --git a/src/host_tracker/host_tracker.h b/src/host_tracker/host_tracker.h index 98d0d0391..77a0ffb9b 100644 --- a/src/host_tracker/host_tracker.h +++ b/src/host_tracker/host_tracker.h @@ -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 diff --git a/src/network_inspectors/rna/rna_app_discovery.cc b/src/network_inspectors/rna/rna_app_discovery.cc index 65e55ea5f..c50fe73fa 100644 --- a/src/network_inspectors/rna/rna_app_discovery.cc +++ b/src/network_inspectors/rna/rna_app_discovery.cc @@ -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()); diff --git a/src/network_inspectors/rna/rna_app_discovery.h b/src/network_inspectors/rna/rna_app_discovery.h index 1a9856b75..dbbefac35 100644 --- a/src/network_inspectors/rna/rna_app_discovery.h +++ b/src/network_inspectors/rna/rna_app_discovery.h @@ -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, diff --git a/src/network_inspectors/rna/rna_pnd.cc b/src/network_inspectors/rna/rna_pnd.cc index 7b6510eb2..020ccef1a 100644 --- a/src/network_inspectors/rna/rna_pnd.cc +++ b/src/network_inspectors/rna/rna_pnd.cc @@ -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());