#endif
#include "host_tracker.h"
-#include "host_cache_allocator.cc"
#include "utils/util.h"
return nullptr;
}
+const uint8_t* HostTracker::get_last_seen_mac()
+{
+ lock_guard<mutex> lck(host_tracker_lock);
+ const HostMac* max_hm = nullptr;
+
+ for ( const auto& hm : macs )
+ if ( !max_hm or max_hm->last_seen < hm.last_seen)
+ max_hm = &hm;
+
+ if ( max_hm )
+ return max_hm->mac;
+
+ return zero_mac;
+}
+
bool HostTracker::update_mac_ttl(const uint8_t* mac, uint8_t new_ttl)
{
if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
p_macs = new list<HostMac>(macs.begin(), macs.end());
}
-bool HostTracker::add_service(Port port, IpProtocol proto, AppId appid, bool inferred_appid, bool* added)
+bool HostTracker::add_service(Port port, IpProtocol proto, AppId appid, bool inferred_appid,
+ bool* added)
{
host_tracker_stats.service_adds++;
lock_guard<mutex> lck(host_tracker_lock);
}
}
- services.emplace_back( HostApplication{port, proto, appid, inferred_appid} );
+ services.emplace_back(port, proto, appid, inferred_appid);
if (added)
*added = true;
return true;
}
-AppId HostTracker::get_appid(Port port, IpProtocol proto, bool inferred_only, bool allow_port_wildcard)
+AppId HostTracker::get_appid(Port port, IpProtocol proto, bool inferred_only,
+ bool allow_port_wildcard)
{
host_tracker_stats.service_finds++;
lock_guard<mutex> lck(host_tracker_lock);
for ( const auto& s : services )
{
- bool matched = (s.port == port and s.proto == proto and (!inferred_only or s.inferred_appid == inferred_only));
+ bool matched = (s.port == port and s.proto == proto and
+ (!inferred_only or s.inferred_appid == inferred_only));
if ( matched or ( allow_port_wildcard and s.inferred_appid ) )
return s.appid;
}
return APP_ID_NONE;
}
+size_t HostTracker::get_service_count()
+{
+ lock_guard<mutex> lck(host_tracker_lock);
+ return services.size();
+}
+
+HostApplication HostTracker::get_service(Port port, IpProtocol proto, uint32_t lseen,
+ bool& is_new, AppId appid)
+{
+ host_tracker_stats.service_finds++;
+ lock_guard<mutex> lck(host_tracker_lock);
+
+ for ( auto& s : services )
+ {
+ if ( s.port == port and s.proto == proto )
+ {
+ if ( s.appid != appid and appid != APP_ID_NONE )
+ {
+ s.appid = appid;
+ is_new = true;
+ }
+ else if ( s.last_seen == 0 )
+ is_new = true;
+ s.last_seen = lseen;
+ ++s.hits;
+ return s;
+ }
+ }
+
+ is_new = true;
+ host_tracker_stats.service_adds++;
+ services.emplace_back(port, proto, appid, false, 1, lseen);
+ return services.back();
+}
+
+void HostTracker::update_service(const HostApplication& ha)
+{
+ host_tracker_stats.service_finds++;
+ lock_guard<mutex> lck(host_tracker_lock);
+
+ for ( auto& s : services )
+ {
+ if ( s.port == ha.port and s.proto == ha.proto )
+ {
+ s.hits = ha.hits;
+ s.last_seen = ha.last_seen;
+ if ( ha.appid > APP_ID_NONE )
+ s.appid = ha.appid;
+ return;
+ }
+ }
+}
+
+bool HostTracker::update_service_info(HostApplication& ha, const char* vendor, const char* version)
+{
+ host_tracker_stats.service_finds++;
+ lock_guard<mutex> lck(host_tracker_lock);
+
+ for ( auto& s : services )
+ {
+ if ( s.port == ha.port and s.proto == ha.proto )
+ {
+ bool changed = false;
+ if ( vendor and strncmp(s.vendor, vendor, INFO_SIZE) )
+ {
+ strncpy(s.vendor, vendor, INFO_SIZE);
+ s.vendor[INFO_SIZE-1] = '\0';
+ changed = true;
+ }
+ if ( version and strncmp(s.version, version, INFO_SIZE) )
+ {
+ strncpy(s.version, version, INFO_SIZE);
+ s.version[INFO_SIZE-1] = '\0';
+ changed = true;
+ }
+ if ( !changed )
+ return false;
+
+ ha.appid = s.appid; // copy these info for the caller
+ ha.hits = s.hits;
+ return true;
+ }
+ }
+ return false;
+}
+
void HostTracker::remove_inferred_services()
{
lock_guard<mutex> lck(host_tracker_lock);
if ( s.inferred_appid )
str += ", inferred";
}
+ if ( s.vendor[0] != '\0' )
+ str += ", vendor: " + string(s.vendor);
+ if ( s.version[0] != '\0' )
+ str += ", version: " + string(s.version);
}
}
namespace snort
{
+#define INFO_SIZE 32
#define MAC_SIZE 6
extern const uint8_t zero_mac[MAC_SIZE];
struct HostApplication
{
+ HostApplication() = default;
+ HostApplication(Port pt, IpProtocol pr, AppId ap, bool in, uint32_t ht = 0, uint32_t ls = 0) :
+ port(pt), proto(pr), appid(ap), inferred_appid(in), hits(ht), last_seen(ls) { }
+
Port port;
IpProtocol proto;
AppId appid;
bool inferred_appid;
+ uint32_t hits;
+ uint32_t last_seen;
+ char vendor[INFO_SIZE] = { 0 };
+ char version[INFO_SIZE] = { 0 };
};
enum HostType
// Returns the matching host_mac
const HostMac* get_hostmac(const uint8_t* mac);
+ const uint8_t* get_last_seen_mac();
+
void update_vlan(uint16_t vth_pri_cfi_vlan, uint16_t vth_proto);
bool has_vlan();
uint16_t get_vlan();
bool add_service(Port port, IpProtocol proto,
AppId appid = APP_ID_NONE, bool inferred_appid = false, bool* added = nullptr);
- AppId get_appid(Port port, IpProtocol proto, bool inferred_only = false, bool allow_port_wildcard = false);
+ AppId get_appid(Port port, IpProtocol proto, bool inferred_only = false,
+ bool allow_port_wildcard = false);
+ size_t get_service_count();
+ HostApplication get_service(Port port, IpProtocol proto, uint32_t lseen, bool& is_new,
+ AppId appid = APP_ID_NONE);
+ void update_service(const HostApplication& ha);
+ bool update_service_info(HostApplication& ha, const char* vendor, const char* version);
void remove_inferred_services();
bool add_tcp_fingerprint(uint32_t fpid);
uint8_t hops; // hops from the snort inspector, e.g., zero for ARP
uint32_t last_seen; // the last time this host was seen
uint32_t last_event; // the last time an event was generated
- std::vector<HostMac, HostMacAllocator> macs;
+ std::list<HostMac, HostMacAllocator> macs; // list guarantees iterator validity on insertion
std::vector<uint16_t, HostCacheAllocIp<uint16_t>> network_protos;
std::vector<uint8_t, HostCacheAllocIp<uint8_t>> xport_protos;
std::vector<HostApplication, HostAppAllocator> services;
typedef LruCacheSharedMemcap<string, Item, hash<string>> CacheType;
CacheType cache(100);
-// Unorthodox, but necessary because we need the implementation of
-// HostCacheAlloc in this file, which we inherit.
-#include "host_tracker/host_cache_allocator.cc"
-
// Implement the allocator constructor AFTER we have a cache object
// to point to and the implementation of our base HostCacheAlloc:
template <class T>
return -1;
}
void DeferredTrust::finalize(Active&) { }
-void DeferredTrust::set_deferred_trust(unsigned module_id, bool on)
+void DeferredTrust::set_deferred_trust(unsigned, bool on)
{
deferred_trust = on ? TRUST_DEFER_ON : TRUST_DEFER_OFF;
}
#include "protocols/packet.h"
#include "pub_sub/appid_events.h"
+#include "utils/util.h"
#include "appid_types.h"
#include "application_ids.h"
virtual void reset()
{
my_id = APP_ID_NONE;
- my_vendor.clear();
my_version.clear();
}
virtual void set_id(const snort::Packet& p, AppIdSession& asd, AppidSessionDirection dir, AppId app_id, AppidChangeBits& change_bits);
- const char* get_vendor() const
- {
- return my_vendor.empty() ? nullptr : my_vendor.c_str();
- }
-
- void set_vendor(const char* vendor)
- {
- if ( vendor )
- my_vendor = vendor;
- }
-
const char* get_version() const
{
return my_version.empty() ? nullptr : my_version.c_str();
private:
AppId my_id = APP_ID_NONE;
- std::string my_vendor;
std::string my_version;
};
+struct AppIdServiceSubtype
+{
+ AppIdServiceSubtype* next = nullptr;
+ std::string service;
+ std::string vendor;
+ std::string version;
+};
+
class ServiceAppDescriptor : public ApplicationDescriptor
{
public:
ServiceAppDescriptor() = default;
+ ~ServiceAppDescriptor() override
+ {
+ AppIdServiceSubtype* tmp_subtype = subtype;
+ while (tmp_subtype)
+ {
+ subtype = tmp_subtype->next;
+ delete tmp_subtype;
+ tmp_subtype = subtype;
+ }
+ }
void set_id(AppId app_id, OdpContext& odp_ctxt);
void reset() override
{
ApplicationDescriptor::reset();
+ my_vendor.clear();
port_service_id = APP_ID_NONE;
+
+ AppIdServiceSubtype* tmp_subtype = subtype;
+ while (tmp_subtype)
+ {
+ subtype = tmp_subtype->next;
+ delete tmp_subtype;
+ tmp_subtype = subtype;
+ }
}
void update_stats(AppId id) override;
return deferred;
}
+ const char* get_vendor() const
+ {
+ return my_vendor.empty() ? nullptr : my_vendor.c_str();
+ }
+
+ void set_vendor(const char* vendor, AppidChangeBits& change_bits)
+ {
+ if ( vendor )
+ {
+ my_vendor = vendor;
+ change_bits.set(APPID_SERVICE_VENDOR_BIT);
+ }
+ }
+
+ void add_subtype(AppIdServiceSubtype& more_subtype, AppidChangeBits& change_bits)
+ {
+ AppIdServiceSubtype** tmp_subtype;
+
+ for (tmp_subtype = &subtype; *tmp_subtype; tmp_subtype = &(*tmp_subtype)->next)
+ ;
+ *tmp_subtype = &more_subtype;
+ change_bits.set(APPID_SERVICE_SUBTYPE_BIT);
+ }
+
+ const AppIdServiceSubtype* get_subtype() const
+ {
+ return subtype;
+ }
+
private:
AppId port_service_id = APP_ID_NONE;
bool deferred = false;
using ApplicationDescriptor::set_id;
+ std::string my_vendor;
+ AppIdServiceSubtype* subtype = nullptr;
};
class ClientAppDescriptor : public ApplicationDescriptor
{
if ( asd.get_service_id() == APP_ID_NONE or asd.get_service_id() == APP_ID_HTTP or
asd.get_service_id() == APP_ID_HTTP2)
+ {
+ char* vendorVersion = nullptr;
+ char* vendor = nullptr;
+ AppIdServiceSubtype* subtype = nullptr;
+
+ http_matchers.get_server_vendor_version(server->c_str(), server->size(),
+ &vendorVersion, &vendor, &subtype);
+ if (vendor || vendorVersion)
{
- char* vendorVersion = nullptr;
- char* vendor = nullptr;
- AppIdServiceSubtype* subtype = nullptr;
-
- http_matchers.get_server_vendor_version(server->c_str(), server->size(),
- &vendorVersion, &vendor, &subtype);
- if (vendor || vendorVersion)
- {
- asd.set_service_vendor(vendor);
- asd.set_service_version(vendorVersion, change_bits);
- asd.scan_flags &= ~SCAN_HTTP_VENDOR_FLAG;
-
- snort_free(vendor);
- snort_free(vendorVersion);
- }
-
- if (subtype)
- {
- AppIdServiceSubtype** tmp_subtype;
-
- for (tmp_subtype = &asd.subtype; *tmp_subtype; tmp_subtype = &(*tmp_subtype)->next)
- ;
-
- *tmp_subtype = subtype;
- }
+ asd.set_service_vendor(vendor, change_bits);
+ asd.set_service_version(vendorVersion, change_bits);
+ asd.scan_flags &= ~SCAN_HTTP_VENDOR_FLAG;
+
+ snort_free(vendor);
+ snort_free(vendorVersion);
}
+
+ if (subtype)
+ asd.add_service_subtype(*subtype, change_bits);
+ }
}
if (is_webdav)
snort_free(netbios_name);
snort_free(netbios_domain);
- AppIdServiceSubtype* rna_ss = subtype;
- while (rna_ss)
- {
- subtype = rna_ss->next;
- snort_free(const_cast<char*>(rna_ss->service));
- snort_free(const_cast<char*>(rna_ss->vendor));
- snort_free(const_cast<char*>(rna_ss->version));
- snort_free(rna_ss);
- rna_ss = subtype;
- }
-
if (tsession)
delete tsession;
APPID_DISCOVERY_STATE service_disco_state = APPID_DISCO_STATE_NONE;
SESSION_SERVICE_SEARCH_STATE service_search_state = SESSION_SERVICE_SEARCH_STATE::START;
ServiceDetector* service_detector = nullptr;
- AppIdServiceSubtype* subtype = nullptr;
std::vector<ServiceDetector*> service_candidates;
// Following field is used only for non-http sessions. For HTTP traffic,
api.service.set_version(version, change_bits);
}
- void set_service_vendor(const char* vendor)
+ void set_service_vendor(const char* vendor, AppidChangeBits& change_bits)
{
- api.service.set_vendor(vendor);
+ api.service.set_vendor(vendor, change_bits);
+ }
+
+ void add_service_subtype(AppIdServiceSubtype& subtype, AppidChangeBits& change_bits)
+ {
+ api.service.add_subtype(subtype, change_bits);
}
AppId get_client_id() const
return application_ids[APP_PROTOID_SERVICE];
}
+void AppIdSessionApi::get_service_info(const char*& vendor, const char*& version,
+ const AppIdServiceSubtype*& subtype) const
+{
+ vendor = service.get_vendor();
+ version = service.get_version();
+ subtype = service.get_subtype();
+}
+
AppId AppIdSessionApi::get_misc_app_id(uint32_t stream_index) const
{
if (get_service_app_id() == APP_ID_HTTP2)
{
public:
AppId get_service_app_id() const;
+ void get_service_info(const char*& vendor, const char*& version,
+ const AppIdServiceSubtype*& subtype) const;
AppId get_misc_app_id(uint32_t stream_index = 0) const;
AppId get_client_app_id(uint32_t stream_index = 0) const;
AppId get_payload_app_id(uint32_t stream_index = 0) const;
AppId get_referred_app_id(uint32_t stream_index = 0) const;
- void get_app_id(AppId& service, AppId& client, AppId& payload, AppId& misc, AppId& referred, uint32_t stream_index = 0) const;
- void get_app_id(AppId* service, AppId* client, AppId* payload, AppId* misc, AppId* referred, uint32_t stream_index = 0) const;
+ void get_app_id(AppId& service, AppId& client, AppId& payload, AppId& misc, AppId& referred,
+ uint32_t stream_index = 0) const;
+ void get_app_id(AppId* service, AppId* client, AppId* payload, AppId* misc, AppId* referred,
+ uint32_t stream_index = 0) const;
bool is_appid_inspecting_session() const;
bool is_appid_available() const;
const char* get_client_version(uint32_t stream_index = 0) const;
const char* get_tls_host() const;
bool is_http_inspection_done() const;
- // For protocols such as HTTP2 which can have multiple streams within a single flow, get_first_stream_*
- // methods return the appids in the first stream seen in a packet.
+ // For protocols such as HTTP2 which can have multiple streams within a single flow,
+ // get_first_stream_* methods return the appids in the first stream seen in a packet.
void get_first_stream_app_ids(AppId& service, AppId& client, AppId& payload, AppId& misc) const;
void get_first_stream_app_ids(AppId& service, AppId& client, AppId& payload) const;
APP_ID_APPID_SESSION_DIRECTION_MAX
};
-struct AppIdServiceSubtype
-{
- AppIdServiceSubtype* next;
- const char* service;
- const char* vendor;
- const char* version;
-};
-
#endif
{
AppIdServiceSubtype* sub = sd->subtype;
sd->subtype = sub->next;
- if (sub->service)
- snort_free((void*)sub->service);
- if (sub->version)
- snort_free((void*)sub->version);
- snort_free(sub);
+ delete sub;
}
ClientPOP3Data* cd = &dd->client;
if (cd->username)
;
if (p == s || p >= line_end || !(*p))
goto ven_ver_done;
- sub = (AppIdServiceSubtype*)snort_calloc(sizeof(AppIdServiceSubtype));
unsigned sub_len;
sub_len = p - s;
- sub->service = (const char*)snort_calloc(sub_len+1);
- memcpy(const_cast<char*>(sub->service), s, sub_len);
- (const_cast<char*>(sub->service))[sub_len] = 0;
+ sub = new AppIdServiceSubtype();
+ sub->service.assign(reinterpret_cast<const char*>(s), sub_len);
sub->next = pd->subtype;
pd->subtype = sub;
if (line_end-p > (int)sizeof(subver_po)-1
if (p != s && p < line_end && *p)
{
sub_len = p - s;
- sub->version = (const char*)snort_calloc(sub_len+1);
- memcpy(const_cast<char*>(sub->version), s, sub_len);
- (const_cast<char*>(sub->version))[sub_len] = 0;
+ sub->version.assign(reinterpret_cast<const char*>(s), sub_len);
}
}
}
{
if ( subname && subname_len > 0 && subver && *subname )
{
- AppIdServiceSubtype* sub =
- (AppIdServiceSubtype*)snort_calloc(
- sizeof(AppIdServiceSubtype));
- char* tmp = (char*)snort_calloc(subname_len + 1);
- memcpy(tmp, subname, subname_len);
- tmp[subname_len] = 0;
- sub->service = tmp;
+ AppIdServiceSubtype* sub = new AppIdServiceSubtype();
+ sub->service.assign(subname, subname_len);
int subver_len = p - subver;
if (subver_len > 0 && *subver)
- {
- tmp = (char*)snort_calloc(subver_len + 1);
- memcpy(tmp, subver, subver_len);
- tmp[subver_len] = 0;
- sub->version = tmp;
- }
+ sub->version.assign(subver, subver_len);
sub->next = *subtype;
*subtype = sub;
}
if ( subname && subname_len > 0 && subver && *subname )
{
- AppIdServiceSubtype* sub =
- (AppIdServiceSubtype*)snort_calloc(sizeof(AppIdServiceSubtype));
- char* tmp = (char*)snort_calloc(subname_len + 1);
- memcpy(tmp, subname, subname_len);
- tmp[subname_len] = 0;
- sub->service = tmp;
+ AppIdServiceSubtype* sub = new AppIdServiceSubtype();
+ sub->service.assign(subname, subname_len);
int subver_len = p - subver;
if ( subver_len > 0 && *subver )
- {
- tmp = (char*)snort_calloc(subver_len + 1);
- memcpy(tmp, subver, subver_len);
- tmp[subver_len] = 0;
- sub->version = tmp;
- }
+ sub->version.assign(subver, subver_len);
sub->next = *subtype;
*subtype = sub;
}
}
class AppIdHttpSession;
class AppIdContext;
+struct AppIdServiceSubtype;
class OdpContext;
enum httpPatternType
return APPID_SUCCESS;
}
-int ServiceDetector::update_service_data(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir, AppId appId,
- const char* vendor, const char* version, AppidChangeBits& change_bits)
+int ServiceDetector::update_service_data(AppIdSession& asd, const Packet* pkt,
+ AppidSessionDirection dir, AppId appId, const char* vendor, const char* version,
+ AppidChangeBits& change_bits, AppIdServiceSubtype* subtype)
{
uint16_t port = 0;
const SfIp* ip = nullptr;
asd.service_detector = this;
- asd.set_service_vendor(vendor);
+ asd.set_service_vendor(vendor, change_bits);
asd.set_service_version(version, change_bits);
+ if (subtype)
+ asd.add_service_subtype(*subtype, change_bits);
asd.set_service_detected();
asd.set_service_id(appId, asd.get_odp_ctxt());
AppidSessionDirection dir, AppId appId, const char* vendor, const char* version,
AppIdServiceSubtype* subtype, AppidChangeBits& change_bits)
{
- asd.subtype = subtype;
- return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits);
+ return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits, subtype);
}
int ServiceDetector::add_service(AppidChangeBits& change_bits, AppIdSession& asd,
const Packet* pkt, AppidSessionDirection dir, AppId appId, const char* vendor,
- const char* version, const AppIdServiceSubtype* subtype)
+ const char* version, AppIdServiceSubtype* subtype)
{
AppIdServiceSubtype* new_subtype = nullptr;
for (; subtype; subtype = subtype->next)
{
- AppIdServiceSubtype* tmp_subtype = (AppIdServiceSubtype*)snort_calloc(
- sizeof(AppIdServiceSubtype));
- if (subtype->service)
- tmp_subtype->service = snort_strdup(subtype->service);
-
- if (subtype->vendor)
- tmp_subtype->vendor = snort_strdup(subtype->vendor);
-
- if (subtype->version)
- tmp_subtype->version = snort_strdup(subtype->version);
+ AppIdServiceSubtype* tmp_subtype = new AppIdServiceSubtype(*subtype);
tmp_subtype->next = new_subtype;
new_subtype = tmp_subtype;
}
- asd.subtype = new_subtype;
- return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits);
+ return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits, new_subtype);
}
int ServiceDetector::incompatible_data(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir)
int add_service(AppidChangeBits&, AppIdSession&, const snort::Packet*,
AppidSessionDirection, AppId, const char* vendor = nullptr,
- const char* version = nullptr, const AppIdServiceSubtype* = nullptr);
+ const char* version = nullptr, AppIdServiceSubtype* = nullptr);
int add_service_consume_subtype(AppIdSession&, const snort::Packet*,
AppidSessionDirection dir, AppId, const char* vendor, const char* version,
}
private:
- int update_service_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId,
- const char* vendor, const char* version, AppidChangeBits& change_bits);
+ int update_service_data(AppIdSession&, const snort::Packet*, AppidSessionDirection, AppId,
+ const char*, const char*, AppidChangeBits&, AppIdServiceSubtype*);
};
#endif
{
if (pname && *pname)
{
- memset(&sub, 0, sizeof(sub));
sub.service = pname;
subtype = ⊂
}
else if (program)
{
snprintf(subname, sizeof(subname), "(%u)", program);
- memset(&sub, 0, sizeof(sub));
sub.service = subname;
subtype = ⊂
}
{
if (pname && *pname)
{
- memset(&sub, 0, sizeof(sub));
sub.service = pname;
subtype = ⊂
}
else if (program)
{
sprintf(subname, "(%u)", program);
- memset(&sub, 0, sizeof(sub));
sub.service = subname;
subtype = ⊂
}
CHECK_EQUAL(service, APPID_UT_ID);
CHECK_EQUAL(client, APPID_UT_ID);
CHECK_EQUAL(payload, APPID_UT_ID);
- STRCMP_EQUAL("Published change_bits == 000000000000000", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000000000000", test_log);
service = APP_ID_NONE;
client = APP_ID_NONE;
STRCMP_EQUAL(mock_session->tsession->get_tls_host(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_first_alt_name(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_cname(), APPID_UT_TLS_HOST);
- STRCMP_EQUAL("Published change_bits == 000000100011000", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000100011000", test_log);
mock_session->tsession->set_tls_host("www.cisco.com", 13, change_bits);
mock_session->tsession->set_tls_cname("www.cisco.com", 13, change_bits);
STRCMP_EQUAL(mock_session->tsession->get_tls_host(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_cname(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_org_unit(), "Cisco");
- STRCMP_EQUAL("Published change_bits == 000000100011000", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000100011000", test_log);
string host = "";
val = appid_api.ssl_app_group_id_lookup(flow, (const char*)(host.c_str()), nullptr,
STRCMP_EQUAL(mock_session->tsession->get_tls_host(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_cname(), APPID_UT_TLS_HOST);
STRCMP_EQUAL(mock_session->tsession->get_tls_org_unit(), "Google");
- STRCMP_EQUAL("Published change_bits == 000000100000000", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000100000000", test_log);
mock().checkExpectations();
}
// Detect changes in service, client, payload, and misc appid
mock().checkExpectations();
- STRCMP_EQUAL("Published change_bits == 000000001111100", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000001111100", test_log);
delete &asd->get_api();
delete asd;
// Detect changes in service, client, payload, and misc appid
mock().checkExpectations();
- STRCMP_EQUAL("Published change_bits == 000000001111100", test_log);
+ STRCMP_EQUAL("Published change_bits == 00000000001111100", test_log);
delete &asd->get_api();
delete asd;
delete flow;
change_bits.set();
change_bits_to_string(change_bits, str);
STRCMP_EQUAL(str.c_str(), "created, reset, service, client, payload, misc, referred, host,"
- " tls-host, url, user-agent, response, referrer, dns-host, version");
+ " tls-host, url, user-agent, response, referrer, dns-host, version, service-vendor, service-subtype");
// Failure of this test is a reminder that enum is changed, hence translator needs update
- CHECK_EQUAL(APPID_MAX_BIT, 15);
+ CHECK_EQUAL(APPID_MAX_BIT, 17);
}
int main(int argc, char** argv)
set_client_user(APPID_UT_ID, APPID_UT_USERNAME);
set_client_version(APPID_UT_CLIENT_VERSION, change_bits);
- set_service_vendor(APPID_UT_SERVICE_VENDOR);
+ set_service_vendor(APPID_UT_SERVICE_VENDOR, change_bits);
set_service_version(APPID_UT_SERVICE_VERSION, change_bits);
- subtype = &APPID_UT_SERVICE_SUBTYPE;
+ add_service_subtype(*(new AppIdServiceSubtype(APPID_UT_SERVICE_SUBTYPE)), change_bits);
tsession = new TlsSession;
set ( RNA_SOURCES
${RNA_INCLUDES}
+ rna_app_discovery.cc
+ rna_app_discovery.h
rna_event_handler.cc
rna_event_handler.h
rna_fingerprint.cc
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// rna_app_discovery.cc authors: Masud Hasan <mashasan@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rna_app_discovery.h"
+
+#include "detection/detection_engine.h"
+#include "network_inspectors/appid/appid_session_api.h"
+
+#include "rna_logger_common.h"
+
+using namespace snort;
+
+void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
+ RnaConfig* conf, RnaLogger& logger)
+{
+ const Packet* p = DetectionEngine::get_current_packet();
+
+ // Published appid events may be on rebuilt packets
+ if ( !p->flow or !filter.is_host_monitored(p) )
+ return;
+
+ IpProtocol proto;
+ if ( p->flow->pkt_type == PktType::TCP )
+ proto = IpProtocol::TCP;
+ else if ( p->flow->pkt_type == PktType::UDP )
+ proto = IpProtocol::UDP;
+ else
+ return;
+
+ const auto& src_ip = p->ptrs.ip_api.get_src();
+ auto ht = host_cache.find(*src_ip);
+ if ( !ht )
+ return; // should not happen as rna would get new flow event before appid event
+
+ const uint8_t* src_mac;
+ if ( layer::get_eth_layer(p) )
+ src_mac = layer::get_eth_layer(p)->ether_src;
+ else
+ src_mac = ht->get_last_seen_mac();
+
+ ht->update_last_seen();
+ const auto& appid_change_bits = appid_event->get_change_bitset();
+ const auto& appid_session_api = appid_event->get_appid_session_api();
+
+ if ( appid_change_bits[APPID_SERVICE_BIT] or appid_change_bits[APPID_CLIENT_BIT] or
+ appid_change_bits[APPID_PAYLOAD_BIT] )
+ {
+ AppId service, client, payload;
+ appid_session_api.get_app_id(&service, &client, &payload, nullptr, nullptr);
+
+ if ( appid_change_bits[APPID_SERVICE_BIT] and service > APP_ID_NONE )
+ discover_service(p, proto, ht, (const struct in6_addr*) src_ip->get_ip6_ptr(),
+ src_mac, conf, logger, service);
+ }
+
+ if ( appid_change_bits[APPID_SERVICE_VENDOR_BIT] or appid_change_bits[APPID_VERSION_BIT] )
+ {
+ const char* vendor;
+ 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);
+ }
+}
+
+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, AppId service)
+{
+ if ( conf and conf->max_host_services and conf->max_host_services <= rt->get_service_count() )
+ return;
+
+ bool is_new = false;
+
+ // Work on a local copy instead of reference as we release lock during event generations
+ auto ha = rt->get_service(p->flow->server_port, proto, (uint32_t) packet_time(), is_new);
+ if ( is_new )
+ {
+ if ( proto == IpProtocol::TCP )
+ logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, &rt, src_ip, src_mac, &ha);
+ else
+ logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, &rt, src_ip, src_mac, &ha);
+
+ ha.hits = 0; // hit count is reset after logs are written
+ ha.appid = service;
+ rt->update_service(ha);
+ }
+}
+
+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)
+{
+ if ( !vendor and !version )
+ return;
+
+ HostApplication ha(p->flow->server_port, proto, APP_ID_NONE, false);
+ if ( !rt->update_service_info(ha, vendor, version) )
+ return;
+
+ // Work on a local copy for eventing purpose
+ ha.last_seen = (uint32_t) packet_time();
+ if ( vendor )
+ {
+ strncpy(ha.vendor, vendor, INFO_SIZE);
+ ha.vendor[INFO_SIZE-1] = '\0';
+ }
+ if ( version )
+ {
+ strncpy(ha.version, version, INFO_SIZE);
+ ha.version[INFO_SIZE-1] = '\0';
+ }
+
+ 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);
+ else
+ logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, &rt,
+ (const struct in6_addr*) ip->get_ip6_ptr(), src_mac, &ha);
+
+ ha.hits = 0;
+ rt->update_service(ha);
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifndef RNA_APP_DISCOVERY_H
+#define RNA_APP_DISCOVERY_H
+
+#include "rna_pnd.h"
+
+class RnaAppDiscovery
+{
+public:
+ static void process(AppidEvent* appid_event, DiscoveryFilter& filter,
+ RnaConfig* conf, RnaLogger& logger);
+
+ static void discover_service(const snort::Packet* p, IpProtocol proto, RnaTracker& rt,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, RnaConfig* conf,
+ RnaLogger& logger, AppId service = APP_ID_NONE);
+
+private:
+ static void update_service_info(const snort::Packet* p, IpProtocol proto, const char* vendor,
+ const char* version, RnaTracker& rt, const snort::SfIp* ip, const uint8_t* src_mac,
+ RnaLogger& logger);
+};
+
+#endif
using namespace snort;
+void RnaAppidEventHandler::handle(DataEvent& event, Flow*)
+{
+ Profile profile(rna_perf_stats);
+ ++rna_stats.appid_change;
+ pnd.analyze_appid_changes(event);
+}
+
void RnaIcmpBidirectionalEventHandler::handle(DataEvent& event, Flow*)
{
Profile profile(rna_perf_stats);
#include "rna_module.h"
#include "rna_pnd.h"
+class RnaAppidEventHandler : public snort::DataHandler
+{
+public:
+ RnaAppidEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { }
+ void handle(snort::DataEvent&, snort::Flow*) override;
+private:
+ RnaPnd& pnd;
+};
+
class RnaIcmpNewFlowEventHandler : public snort::DataHandler
{
public:
{
mod_conf = mod->get_config();
load_rna_conf();
- time_t update_timeout = rna_conf ? rna_conf->update_timeout : 0;
if ( mod_conf )
- pnd = new RnaPnd(mod_conf->enable_logger, mod_conf->rna_conf_path, update_timeout);
+ pnd = new RnaPnd(mod_conf->enable_logger, mod_conf->rna_conf_path, rna_conf);
else
- pnd = new RnaPnd(false, "", update_timeout);
+ pnd = new RnaPnd(false, "", rna_conf);
}
RnaInspector::~RnaInspector()
bool RnaInspector::configure(SnortConfig* sc)
{
+ DataBus::subscribe_global( APPID_EVENT_ANY_CHANGE, new RnaAppidEventHandler(*pnd), sc );
+
DataBus::subscribe_global( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpNewFlowEventHandler(*pnd), sc );
DataBus::subscribe_global( STREAM_ICMP_BIDIRECTIONAL_EVENT, new RnaIcmpBidirectionalEventHandler(*pnd), sc );
#include "managers/event_manager.h"
#include "protocols/packet.h"
+
#include "rna_fingerprint_tcp.h"
#include "rna_logger_common.h"
+#include "rna_module.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
using namespace snort;
-bool RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
- const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t event_time,
- void* cond_var, const HostMac* hm, const uint16_t proto,
- const TcpFingerprint* tfp)
+#ifdef DEBUG_MSGS
+static inline void rna_logger_message(const RnaLoggerEvent& rle)
+{
+ char macbuf[19];
+ snprintf(macbuf, 19, "%02X:%02X:%02X:%02X:%02X:%02X",
+ rle.mac[0], rle.mac[1], rle.mac[2], rle.mac[3], rle.mac[4], rle.mac[5]);
+ if ( rle.ip )
+ {
+ SfIp ip;
+ SfIpString ipbuf;
+ ip.set(rle.ip); // using this instead of packet's ip to support ARP
+ debug_logf(rna_trace, nullptr, "RNA log: type %u, subtype %u, mac %s, ip %s\n",
+ rle.type, rle.subtype, macbuf, ip.ntop(ipbuf));
+ }
+ else
+ debug_logf(rna_trace, nullptr, "RNA log: type %u, subtype %u, mac %s\n",
+ rle.type, rle.subtype, macbuf);
+}
+#endif
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const HostApplication* ha)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, 0, 0,
+ nullptr, ha, nullptr, nullptr);
+}
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const TcpFingerprint* tfp)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, 0, 0,
+ nullptr, nullptr, tfp, nullptr);
+}
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t event_time)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, event_time, 0,
+ nullptr, nullptr, nullptr, nullptr);
+}
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const HostMac* hm, uint32_t event_time)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, event_time, 0,
+ hm, nullptr, nullptr, nullptr);
+}
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+ uint16_t proto, const uint8_t* src_mac, const struct in6_addr* src_ip, uint32_t event_time)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, event_time, proto,
+ nullptr, nullptr, nullptr, nullptr);
+}
+
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const uint8_t* src_mac,
+ const struct in6_addr* src_ip, RnaTracker* ht, uint32_t event_time, void* cond_var)
+{
+ log(type, subtype, src_ip, src_mac, ht, p, event_time, 0,
+ nullptr, nullptr, nullptr, cond_var);
+}
+
+bool RnaLogger::log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip,
+ const uint8_t* src_mac, RnaTracker* ht, const Packet* p, uint32_t event_time,
+ uint16_t proto, const HostMac* hm, const HostApplication* ha, const TcpFingerprint* tfp,
+ void* cond_var)
{
if ( !enabled )
return false;
assert(ht);
- RnaLoggerEvent rle(type, subtype, ht, src_mac, hm, proto, tfp);
+
+ RnaLoggerEvent rle(type, subtype, src_mac, ht, hm, proto, cond_var, ha, tfp);
if ( src_ip and (!IN6_IS_ADDR_V4MAPPED(src_ip) or src_ip->s6_addr32[3]) )
rle.ip = src_ip;
-
+ else
+ rle.ip = nullptr;
if ( event_time )
(*ht)->update_last_event(event_time);
- if ( subtype == CHANGE_HOST_UPDATE and type == RNA_EVENT_CHANGE )
- rle.cond_var = cond_var;
EventManager::call_loggers(nullptr, const_cast<Packet*>(p), "RNA", &rle);
+
+#ifdef DEBUG_MSGS
+ rna_logger_message(rle);
+#endif
return true;
}
SECTION("Checking enabled flag")
{
RnaTracker ht;
+ uint8_t mac[6] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6};
RnaLogger logger1(false);
- CHECK(logger1.log(0, 0, 0, &ht, 0, 0) == false);
+ CHECK(logger1.log(0, 0, nullptr, mac, &ht, nullptr, 0, 0,
+ nullptr, nullptr, nullptr, nullptr) == false);
RnaLogger logger2(true);
- CHECK(logger2.log(0, 0, 0, &ht, 0, 0) == true);
+ CHECK(logger2.log(0, 0, nullptr, mac, &ht, nullptr, 0, 0,
+ nullptr, nullptr, nullptr, nullptr) == true);
}
}
#endif
struct RnaLoggerEvent : public Event
{
- RnaLoggerEvent(uint16_t p_type, uint16_t p_subtype, const RnaTracker* p_ht,
- const uint8_t* p_mac, const snort::HostMac* p_hm, const uint16_t p_proto,
- const snort::TcpFingerprint* tcp_fp)
- : type(p_type), subtype(p_subtype), ht(p_ht), mac(p_mac), hm(p_hm), proto(p_proto), tfp(tcp_fp) { }
+ RnaLoggerEvent (uint16_t t, uint16_t st, const uint8_t* mc, const RnaTracker* rt,
+ const snort::HostMac* hmp, uint16_t pr, void* cv, const snort::HostApplication* hap,
+ const snort::TcpFingerprint* tf) : type(t), subtype(st), mac(mc), ht(rt), hm(hmp),
+ proto(pr), cond_var(cv), ha(hap), tfp(tf) { }
+
uint16_t type;
uint16_t subtype;
- const RnaTracker* ht;
+ const struct in6_addr* ip;
const uint8_t* mac;
- const struct in6_addr* ip = nullptr;
- void* cond_var = nullptr;
+ const RnaTracker* ht;
const snort::HostMac* hm;
- const uint16_t proto;
- const snort::TcpFingerprint* tfp = nullptr;
+ uint16_t proto;
+ void* cond_var;
+ const snort::HostApplication* ha;
+ const snort::TcpFingerprint* tfp;
};
class RnaLogger
{
public:
RnaLogger(const bool enable) : enabled(enable) { }
- bool log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
- const struct in6_addr* src_ip, const uint8_t* src_mac,
- uint32_t event_time = 0, void* cond_var = nullptr,
- const snort::HostMac* hm = nullptr, const uint16_t proto = 0,
- const snort::TcpFingerprint* tfp = nullptr);
+
+ // for host application
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::HostApplication* ha);
+
+ // for tcp fingerprint
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::TcpFingerprint* tfp);
+
+ // for event time
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t event_time);
+
+ // for mac event
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ const struct in6_addr* src_ip, const uint8_t* src_mac,
+ const snort::HostMac* hm = nullptr, uint32_t event_time = 0);
+
+ // for protocol event
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ uint16_t proto, const uint8_t* mac, const struct in6_addr* ip = nullptr,
+ uint32_t event_time = 0);
+
+ // for timeout update
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, const uint8_t* src_mac,
+ const struct in6_addr* src_ip, RnaTracker* ht, uint32_t event_time, void* cond_var);
+
+ // for all
+ bool log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip,
+ const uint8_t* src_mac, RnaTracker* ht, const snort::Packet* p = nullptr,
+ uint32_t event_time = 0, uint16_t proto = 0, const snort::HostMac* hm = nullptr,
+ const snort::HostApplication* ha = nullptr, const snort::TcpFingerprint* tfp = nullptr,
+ void* cond_var = nullptr);
private:
const bool enabled;
// Common definitions between rna logger and pnd modules
#define RNA_EVENT_NEW 1000
#define NEW_HOST 1
+ #define NEW_TCP_SERVICE 2
#define NEW_NET_PROTOCOL 3
#define NEW_XPORT_PROTOCOL 4
+ #define NEW_UDP_SERVICE 6
#define NEW_OS 8
#define RNA_EVENT_CHANGE 1001
#define CHANGE_HOPS 5
+ #define CHANGE_TCP_SERVICE_INFO 6
+ #define CHANGE_UDP_SERVICE_INFO 10
#define CHANGE_MAC_INFO 13
#define CHANGE_MAC_ADD 14
#define CHANGE_HOST_UPDATE 15
uint32_t last_seen = 0;
uint32_t last_event = 0;
bool vlan_tag_present = false;
- snort::vlan::VlanTagHdr vlan_tag;
+ snort::vlan::VlanTagHdr vlan_tag = { };
std::vector<uint16_t, HostCacheAllocMac<uint16_t>> network_protos;
};
using namespace snort;
using namespace std;
+THREAD_LOCAL const Trace* rna_trace = nullptr;
+
//-------------------------------------------------------------------------
// rna commands, params, and pegs
//-------------------------------------------------------------------------
static const PegInfo rna_pegs[] =
{
+ { CountType::SUM, "appid_change", "count of appid change events received" },
{ CountType::SUM, "icmp_bidirectional", "count of bidirectional ICMP flows received" },
{ CountType::SUM, "icmp_new", "count of new ICMP flows received" },
{ CountType::SUM, "ip_bidirectional", "count of bidirectional IP received" },
ProfileStats* RnaModule::get_profile() const
{ return &rna_perf_stats; }
+void RnaModule::set_trace(const Trace* trace) const
+{ rna_trace = trace; }
+
+const TraceOption* RnaModule::get_trace_options() const
+{
+ static const TraceOption rna_trace_options(nullptr, 0, nullptr);
+ return &rna_trace_options;
+}
+
bool RnaModule::log_mac_cache(const char* outfile)
{
if ( !outfile )
#define RNA_MODULE_H
#include "framework/module.h"
+#include "main/snort_debug.h"
#include "profiler/profiler.h"
#include "rna_config.h"
struct RnaStats
{
+ PegCount appid_change;
PegCount icmp_bidirectional;
PegCount icmp_new;
PegCount ip_bidirectional;
extern THREAD_LOCAL RnaStats rna_stats;
extern THREAD_LOCAL snort::ProfileStats rna_perf_stats;
+extern THREAD_LOCAL const snort::Trace* rna_trace;
class RnaModule : public snort::Module
{
Usage get_usage() const override
{ return CONTEXT; }
+ void set_trace(const snort::Trace*) const override;
+ const snort::TraceOption* get_trace_options() const override;
+
private:
RnaModuleConfig* mod_conf = nullptr;
const char* dump_file = nullptr;
#include "protocols/arp.h"
#include "protocols/bpdu.h"
#include "protocols/icmp4.h"
-#include "protocols/packet.h"
#include "protocols/protocol_ids.h"
-#include "protocols/tcp.h"
+#include "rna_app_discovery.h"
#include "rna_fingerprint_tcp.h"
#include "rna_logger_common.h"
using namespace snort::bpdu;
using namespace std;
-static inline bool is_eligible_packet(const Packet* p)
+void RnaPnd::analyze_appid_changes(DataEvent& event)
{
- if ( p->has_ip() or
- memcmp(layer::get_eth_layer(p)->ether_src, zero_mac, MAC_SIZE) )
- return true;
- return false;
-}
-
-static inline bool is_eligible_ip(const Packet* p)
-{
- // If payload needs to be inspected ever, allow rebuilt packet when is_proxied
- if ( !p->has_ip() or p->is_rebuilt() or !p->flow )
- return false;
- return true;
-}
-
-static inline bool is_eligible_tcp(const Packet* p)
-{
- if ( !is_eligible_ip(p) or p->ptrs.tcph->is_rst() )
- return false;
- return true;
-}
-
-static inline bool is_eligible_udp(const Packet* p)
-{
- if ( !is_eligible_ip(p) )
- return false;
- if ( p->is_from_client() )
- {
- const SfIp* src = p->ptrs.ip_api.get_src();
- const SfIp* dst = p->ptrs.ip_api.get_dst();
- // FIXIT-M this code checking the v6 address unconditionally is almost certainly wrong,
- // especially since it's looking for an IPv4-specific protocol
- if ( !src->is_set() and ((const uint8_t *) dst->get_ip6_ptr())[0] == 0XFF and
- p->ptrs.sp == 68 and p->ptrs.dp == 67 )
- return false; // skip BOOTP
- }
- return true;
+ RnaAppDiscovery::process(static_cast<AppidEvent*>(&event), filter, conf, logger);
}
void RnaPnd::analyze_flow_icmp(const Packet* p)
if ( new_mac and !new_host )
logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_ADD, p, &ht,
- src_ip_ptr, src_mac, packet_time(), nullptr, ht->get_hostmac(src_mac));
+ src_ip_ptr, src_mac, ht->get_hostmac(src_mac), packet_time());
if ( ht->update_mac_ttl(src_mac, ttl) )
{
logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, &ht,
- src_ip_ptr, src_mac, packet_time(), nullptr, ht->get_hostmac(src_mac));
+ src_ip_ptr, src_mac, ht->get_hostmac(src_mac), packet_time());
HostMac* hm = ht->get_max_ttl_hostmac();
if (hm and hm->primary and ht->get_hops())
if ( ptype > to_utype(ProtocolId::ETHERTYPE_MINIMUM) )
{
if ( ht->add_network_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, src_ip_ptr, src_mac,
- packet_time(), nullptr, nullptr, ptype);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
+ packet_time());
}
ptype = to_utype(p->get_ip_proto_next());
if ( ht->add_xport_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, &ht, src_ip_ptr, src_mac,
- packet_time(), nullptr, nullptr, ptype);
+ 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);
+ }
if ( !new_host )
{
const TcpFingerprint* tfp = processor->get(p, rna_flow);
if (tfp && ht->add_tcp_fingerprint(tfp->fpid))
- {
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &ht, src_ip_ptr,
- src_mac, 0, nullptr, nullptr, ptype, tfp);
- }
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, &ht, src_ip_ptr, src_mac, tfp);
}
}
update_vlan(p, hm);
rt->get()->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
- logger.log(RNA_EVENT_CHANGE, CHANGE_VLAN_TAG, p, rt, nullptr,
- src_mac, rt->get()->get_last_seen());
+ logger.log(RNA_EVENT_CHANGE, CHANGE_VLAN_TAG, p, rt, nullptr, src_mac, packet_time());
}
}
{
rt->get()->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
logger.log(RNA_EVENT_CHANGE, CHANGE_VLAN_TAG, p, rt,
- (const struct in6_addr*) src_ip->get_ip6_ptr(),
- src_mac, rt->get()->get_last_seen());
+ (const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac, packet_time());
}
}
uint32_t last_event = (*ht)->get_last_event();
time_t timestamp = sec - update_timeout;
if ( last_seen > last_event && (time_t) last_event + update_timeout <= sec )
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, ht,
- (const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac, last_seen, (void*) ×tamp);
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, src_mac,
+ (const struct in6_addr*) src_ip->get_ip6_ptr(), ht, last_seen, (void*) ×tamp);
// FIXIT-M: deal with host service hits.
}
if ( last_seen > last_event && (time_t) last_event + update_timeout <= sec )
{
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, &rt,
- nullptr, src_mac, last_seen, (void*) ×tamp);
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, src_mac, nullptr,
+ &rt, last_seen, (void*) ×tamp);
mt->update_last_event(sec);
}
{
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, nullptr, mk.mac_addr,
- 0, nullptr, nullptr, ntype);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
}
ntype = ((const RNA_LLC*) lyr.start)->s.proto;
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, nullptr, mk.mac_addr,
- 0, nullptr, nullptr, ntype);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
}
if ( ht->add_mac(src_mac, 0, 0) )
{
logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_ADD, p, ht_ref,
- (const struct in6_addr*) spa.get_ip6_ptr(), src_mac,
- 0, nullptr, ht->get_hostmac(src_mac));
+ (const struct in6_addr*) spa.get_ip6_ptr(), src_mac, ht->get_hostmac(src_mac));
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
else if (ht->make_primary(src_mac))
{
logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, ht_ref,
- (const struct in6_addr*) spa.get_ip6_ptr(), src_mac,
- 0, nullptr, ht->get_hostmac(src_mac));
+ (const struct in6_addr*) spa.get_ip6_ptr(), src_mac, ht->get_hostmac(src_mac));
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, nullptr, src_mac,
- 0, nullptr, nullptr, ntype);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, src_mac);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
{
ht->update_hops(0);
logger.log(RNA_EVENT_CHANGE, CHANGE_HOPS, p, ht_ref,
- (const struct in6_addr*) spa.get_ip6_ptr(), src_mac, 0, nullptr,
- ht->get_hostmac(src_mac));
+ (const struct in6_addr*) spa.get_ip6_ptr(), src_mac, ht->get_hostmac(src_mac));
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
#include "host_tracker/host_tracker.h"
#include "protocols/eth.h"
#include "protocols/layer.h"
+#include "protocols/packet.h"
+#include "protocols/tcp.h"
#include "protocols/vlan.h"
+#include "pub_sub/appid_events.h"
#include "sfip/sf_ip.h"
+#include "rna_config.h"
#include "rna_logger.h"
#include "rna_mac_cache.h"
#define USHRT_MAX std::numeric_limits<unsigned short>::max()
-namespace snort
-{
-struct Packet;
-}
-
enum class TcpPacketType
{
SYN, SYN_ACK, MIDSTREAM
};
#pragma pack()
+static inline bool is_eligible_packet(const snort::Packet* p)
+{
+ if ( p->has_ip() or
+ memcmp(snort::layer::get_eth_layer(p)->ether_src, snort::zero_mac, MAC_SIZE) )
+ return true;
+ return false;
+}
+
+static inline bool is_eligible_ip(const snort::Packet* p)
+{
+ // If payload needs to be inspected ever, allow rebuilt packet when is_proxied
+ if ( !p->has_ip() or p->is_rebuilt() or !p->flow )
+ return false;
+ return true;
+}
+
+static inline bool is_eligible_tcp(const snort::Packet* p)
+{
+ if ( !is_eligible_ip(p) or p->ptrs.tcph->is_rst() )
+ return false;
+ return true;
+}
+
+static inline bool is_eligible_udp(const snort::Packet* p)
+{
+ if ( !is_eligible_ip(p) )
+ return false;
+ if ( p->is_from_client() )
+ {
+ const snort::SfIp* src = p->ptrs.ip_api.get_src();
+ const snort::SfIp* dst = p->ptrs.ip_api.get_dst();
+ // FIXIT-M this code checking the v6 address unconditionally is almost certainly wrong,
+ // especially since it's looking for an IPv4-specific protocol
+ if ( !src->is_set() and ((const uint8_t *) dst->get_ip6_ptr())[0] == 0XFF and
+ p->ptrs.sp == 68 and p->ptrs.dp == 67 )
+ return false; // skip BOOTP
+ }
+ return true;
+}
+
static inline unsigned short rna_get_eth(const snort::Packet* p)
{
const snort::vlan::VlanTagHdr* vh = nullptr;
{
public:
- RnaPnd(const bool en, const std::string& conf, time_t ut = 0)
- : logger(RnaLogger(en)), filter(DiscoveryFilter(conf)), update_timeout(ut) { }
+ RnaPnd(const bool en, const std::string& cp, RnaConfig* rc = nullptr) :
+ logger(RnaLogger(en)), filter(DiscoveryFilter(cp)), conf(rc)
+ { update_timeout = (rc ? rc->update_timeout : 0); }
+ void analyze_appid_changes(snort::DataEvent& event);
void analyze_flow_icmp(const snort::Packet* p);
void analyze_flow_ip(const snort::Packet* p);
void analyze_flow_non_ip(const snort::Packet* p);
RnaLogger logger;
DiscoveryFilter filter;
+ RnaConfig* conf;
time_t update_timeout;
};
// other
APPID_VERSION_BIT,
+ APPID_SERVICE_VENDOR_BIT,
+ APPID_SERVICE_SUBTYPE_BIT,
APPID_MAX_BIT
};
--n? str.append("dns-host, ") : str.append("dns-host");
if (change_bits.test(APPID_VERSION_BIT))
--n? str.append("version, ") : str.append("version");
+ if (change_bits.test(APPID_SERVICE_VENDOR_BIT))
+ --n? str.append("service-vendor, ") : str.append("service-vendor");
+ if (change_bits.test(APPID_SERVICE_SUBTYPE_BIT))
+ --n? str.append("service-subtype, ") : str.append("service-subtype");
if (n != 0) // make sure all bits from AppidChangeBit enum get translated
str.append("change_bits_to_string error!");
}