return result.second;
}
+DeviceFingerprint::DeviceFingerprint(uint32_t id, uint32_t type, bool jb, const char* dev) :
+ fpid(id), fp_type(type), jail_broken(jb)
+{
+ if ( dev )
+ {
+ strncpy(device, dev, INFO_SIZE);
+ device[INFO_SIZE-1] = '\0';
+ }
+}
+
+bool HostTracker::add_ua_fingerprint(uint32_t fpid, uint32_t fp_type, bool jail_broken,
+ const char* device, uint8_t max_devices)
+{
+ lock_guard<mutex> lck(host_tracker_lock);
+
+ int count = 0;
+ for ( const auto& fp : ua_fps )
+ {
+ if ( fpid != fp.fpid or fp_type != fp.fp_type )
+ continue;
+ ++count; // only count same fpid with different device information
+ if ( count >= max_devices )
+ return false;
+ if ( jail_broken == fp.jail_broken and ( ( !device and fp.device[0] == '\0') or
+ ( device and strncmp(fp.device, device, INFO_SIZE) == 0) ) )
+ return false;
+ }
+
+ ua_fps.emplace_back(fpid, fp_type, jail_broken, device);
+ return true;
+}
+
size_t HostTracker::get_client_count()
{
lock_guard<mutex> lck(host_tracker_lock);
for ( const auto& fpid : tcp_fpids )
str += to_string(fpid) + (--total ? ", " : "");
}
+
+ total = ua_fps.size();
+ if ( total )
+ {
+ str += "\nua fingerprint: ";
+ for ( const auto& fp : ua_fps )
+ {
+ str += to_string(fp.fpid) + " (type: " + to_string(fp.fp_type);
+ if ( fp.jail_broken )
+ str += ", jail-broken";
+ if ( fp.device[0] != '\0' )
+ str += ", device: " + string(fp.device);
+ str += string(")") + (--total ? ", " : "");
+ }
+ }
}
AppId service;
};
+struct DeviceFingerprint
+{
+ DeviceFingerprint(uint32_t id, uint32_t type, bool jb, const char* dev);
+ uint32_t fpid;
+ uint32_t fp_type;
+ bool jail_broken;
+ char device[INFO_SIZE] = { 0 };
+};
+
enum HostType
{
HOST_TYPE_HOST=0,
typedef HostCacheAllocIp<HostMac> HostMacAllocator;
typedef HostCacheAllocIp<HostApplication> HostAppAllocator;
typedef HostCacheAllocIp<HostClient> HostClientAllocator;
+typedef HostCacheAllocIp<DeviceFingerprint> HostDeviceFpAllocator;
class SO_PUBLIC HostTracker
{
size_t get_client_count();
HostClient get_client(AppId id, const char* version, AppId service, bool& is_new);
bool add_tcp_fingerprint(uint32_t fpid);
+ bool add_ua_fingerprint(uint32_t fpid, uint32_t fp_type, bool jail_broken,
+ const char* device_info, uint8_t max_devices);
// This should be updated whenever HostTracker data members are changed
void stringify(std::string& str);
std::vector<HostApplication, HostAppAllocator> services;
std::vector<HostClient, HostClientAllocator> clients;
std::set<uint32_t, std::less<uint32_t>, HostCacheAllocIp<uint32_t>> tcp_fpids;
+ std::vector<DeviceFingerprint, HostDeviceFpAllocator> ua_fps;
bool vlan_tag_present = false;
vlan::VlanTagHdr vlan_tag;
set (RNA_INCLUDES
rna_fingerprint.h
rna_fingerprint_tcp.h
+ rna_fingerprint_ua.h
rna_inspector.h
rna_logger.h
rna_name.h
rna_fingerprint.cc
rna_fingerprint.h
rna_fingerprint_tcp.cc
- rna_fingerprint_tcp.h
+ rna_fingerprint_ua.cc
rna_inspector.cc
rna_inspector.h
rna_logger.cc
ws: window scale
FpElementType::RANGE
FpElementType::DONT_CARE
+
+Similar to the TCP fingerprints, user-agent based fingerprints loads different types of
+fingerprint patterns from Lua configuration, namely os (operating system), device
+(mobile device information), jail-broken (hacked system), and jail-broken-host
+(host information of the hacked system to confirm matching). During packet processing,
+the rna module depends on the HTTP user agent and host information found by the appid
+module and tries to match all parts of user-agent patterns. A sample configuration
+looks like this:
+{
+ fpid = 1,
+ uuid = "10000000-0000-0000-0000-111111111111",
+ ua_type = "device",
+ user_agent = { { substring = "CPU" }, { substring = "OS 3_0" }, { substring = "My Company" } },
+ device = "My Mobile",
+}
#include "detection/detection_engine.h"
#include "network_inspectors/appid/appid_session_api.h"
+#include "rna_fingerprint_ua.h"
#include "rna_logger_common.h"
using namespace snort;
appid_session_api.get_service_info(vendor, version, subtype);
update_service_info(p, proto, vendor, version, ht, src_ip, src_mac, logger);
}
+
+ if ( p->is_from_client() and ( appid_change_bits[APPID_HOST_BIT] or
+ appid_change_bits[APPID_USERAGENT_BIT] ) )
+ {
+ const AppIdHttpSession* hsession;
+
+ if ( appid_event->get_is_http2() )
+ hsession = appid_session_api.get_http_session(appid_event->get_http2_stream_index());
+ else
+ hsession = appid_session_api.get_http_session();
+
+ if ( hsession )
+ {
+ const char* host = hsession->get_cfield(REQ_HOST_FID);
+ const char* uagent = hsession->get_cfield(REQ_AGENT_FID);
+ analyze_user_agent_fingerprint(p, host, uagent, ht, src_ip, src_mac, logger);
+ }
+ }
}
void RnaAppDiscovery::discover_service(const Packet* p, IpProtocol proto, RnaTracker& rt,
logger.log(RNA_EVENT_NEW, NEW_CLIENT_APP, p, &rt, src_ip, src_mac, &hc);
}
}
+
+void RnaAppDiscovery::analyze_user_agent_fingerprint(const Packet* p, const char* host,
+ const char* uagent, RnaTracker& rt, const SfIp* ip, const uint8_t* src_mac, RnaLogger& logger)
+{
+ if ( !host or !uagent )
+ return;
+
+ const auto& processor = get_ua_fp_processor();
+ if ( !processor )
+ return;
+
+ const UaFingerprint* uafp = nullptr;
+ const char* device_info = nullptr;
+ bool jail_broken = false;
+ processor->match_mpse(host, uagent, uafp, device_info, jail_broken);
+
+ if ( uafp and rt->add_ua_fingerprint(uafp->fpid, uafp->fp_type, jail_broken,
+ device_info, MAX_USER_AGENT_DEVICES) )
+ {
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, &rt, (const struct in6_addr*)ip->get_ip6_ptr(),
+ src_mac, (FpFingerprint*)uafp);
+ }
+}
+
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);
+ static void analyze_user_agent_fingerprint(const snort::Packet* p, const char* host,
+ const char* uagent, RnaTracker& rt, const snort::SfIp* ip, const uint8_t* src_mac,
+ RnaLogger& logger);
};
#endif
namespace snort
{
class TcpFpProcessor;
+class UaFpProcessor;
}
struct RnaModuleConfig
std::string rna_conf_path;
bool enable_logger;
bool log_when_idle;
- snort::TcpFpProcessor* processor = nullptr;
+ snort::TcpFpProcessor* tcp_processor = nullptr;
+ snort::UaFpProcessor* ua_processor = nullptr;
};
// Give default values so that RNA can work even if rna_conf_path is not provided
#include <cstdint>
#include <string>
+#include <vector>
#include "main/snort_types.h"
}
+enum UserAgentInfoType
+{
+ OS_INFO,
+ DEVICE_INFO,
+ JAIL_BROKEN_INFO,
+ JAIL_BROKEN_HOST
+};
+
class RawFingerprint
{
public:
std::string ws;
bool df = false;
+ UserAgentInfoType ua_type = OS_INFO;
+ std::vector<std::string> user_agent;
+ std::string host_name;
+ std::string device;
+
void clear()
{
fpid = 0;
id.clear();
topts.clear();
ws.clear();
- df=false;
+ df = false;
+ ua_type = OS_INFO;
+ user_agent.clear();
+ host_name.clear();
+ device.clear();
}
-
};
#endif
--- /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_fingerprint_ua.cc author Masud Hasan <mashasan@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rna_fingerprint_ua.h"
+
+#include <algorithm>
+#include <cstring>
+
+#include "main/thread.h"
+
+using namespace snort;
+using namespace std;
+
+static THREAD_LOCAL UaFpProcessor* ua_fp_processor = nullptr;
+
+UaFpProcessor* get_ua_fp_processor()
+{
+ return ua_fp_processor;
+}
+
+void set_ua_fp_processor(UaFpProcessor* processor)
+{
+ ua_fp_processor = processor;
+}
+
+bool UaFingerprint::operator==(const UaFingerprint& y) const
+{
+ return fpid == y.fpid and part_num == y.part_num and total_parts == y.total_parts;
+}
+
+UaFpProcessor::~UaFpProcessor()
+{
+ delete os_mpse;
+ delete device_mpse;
+ delete jb_mpse;
+ delete jb_host_mpse;
+}
+
+void UaFpProcessor::push(const RawFingerprint& rfp)
+{
+ if ( rfp.ua_type == JAIL_BROKEN_HOST )
+ {
+ if ( rfp.host_name.empty() )
+ return;
+ UaFingerprint uafp;
+ uafp.fpid = rfp.fpid;
+ uafp.fpuuid = rfp.fpuuid;
+ uafp.fp_type = FpFingerprint::FpType::FP_TYPE_MOBILE;
+ uafp.host_name = rfp.host_name;
+ uafp.part_num = 0;
+ uafp.total_parts = 1;
+ push_jb_host(uafp);
+ }
+ else
+ {
+ for (size_t i = 0; i < rfp.user_agent.size(); ++i)
+ {
+ UaFingerprint uafp;
+ uafp.fpid = rfp.fpid;
+ uafp.fpuuid = rfp.fpuuid;
+ uafp.user_agent = rfp.user_agent[i];
+ uafp.part_num = i;
+ uafp.total_parts = rfp.user_agent.size();
+ if ( rfp.ua_type == OS_INFO )
+ {
+ uafp.fp_type = FpFingerprint::FpType::FP_TYPE_USERAGENT;
+ push_agent(uafp);
+ }
+ else if ( rfp.ua_type == DEVICE_INFO )
+ {
+ uafp.device = rfp.device;
+ uafp.fp_type = FpFingerprint::FpType::FP_TYPE_MOBILE;
+ push_device(uafp);
+ }
+ else
+ {
+ uafp.fp_type = FpFingerprint::FpType::FP_TYPE_MOBILE;
+ push_jb(uafp);
+ }
+ }
+ }
+}
+
+void UaFpProcessor::make_mpse(SnortConfig* sc)
+{
+ SearchTool::set_conf(sc);
+ if ( !os_fps.empty() )
+ {
+ os_mpse = new SearchTool;
+ for (auto& fp : os_fps)
+ os_mpse->add(fp.user_agent.c_str(), fp.user_agent.size(), &fp);
+ os_mpse->prep();
+ }
+
+ if ( !device_fps.empty() )
+ {
+ device_mpse = new SearchTool;
+ for (auto& fp : device_fps)
+ device_mpse->add(fp.user_agent.c_str(), fp.user_agent.size(), &fp);
+ device_mpse->prep();
+ }
+
+ if ( !jb_fps.empty() )
+ {
+ jb_mpse = new SearchTool;
+ for (auto& fp : jb_fps)
+ jb_mpse->add(fp.user_agent.c_str(), fp.user_agent.size(), &fp);
+ jb_mpse->prep();
+ }
+
+ if ( !jb_host_fps.empty() )
+ {
+ jb_host_mpse = new SearchTool;
+ for (auto& fp : jb_host_fps)
+ jb_host_mpse->add(fp.host_name.c_str(), fp.host_name.size(), &fp);
+ jb_host_mpse->prep();
+ }
+ SearchTool::set_conf(nullptr);
+}
+
+static int match_ua_part(void* id, void*, int, void* data, void*)
+{
+ auto cur_fp = (UaFingerprint*) id;
+ auto matched_parts = (vector<UaFingerprint*>*)data;
+
+ for (const auto& fp : *matched_parts)
+ if ( *fp == *cur_fp )
+ return 0; // ignore already recorded matching part
+
+ matched_parts->emplace_back(cur_fp);
+ return 0; // search continues for the next match
+}
+
+struct CompareParts
+{
+ bool operator()(const UaFingerprint* p1, const UaFingerprint* p2) const
+ {
+ return (p1->fpid < p2->fpid) or (p1->fpid == p2->fpid and p1->part_num < p2->part_num);
+ }
+};
+
+static inline UaFingerprint* search_ua_fp(SearchTool* mpse, const char* start, unsigned len)
+{
+ if ( !mpse )
+ return nullptr;
+
+ vector<UaFingerprint*> matched_parts;
+ mpse->find_all(start, len, match_ua_part, false, (void*)&matched_parts);
+ if ( matched_parts.empty() )
+ return nullptr;
+
+ sort(matched_parts.begin(), matched_parts.end(), CompareParts());
+
+ uint32_t cur_fpid = 0, part_num = 0;
+ for (auto& fp : matched_parts)
+ {
+ if ( cur_fpid != fp->fpid )
+ {
+ cur_fpid = fp->fpid;
+ part_num = 0;
+ }
+
+ if ( part_num == fp->part_num )
+ {
+ if ( ++part_num == fp->total_parts )
+ return fp;
+ }
+ }
+ return nullptr;
+}
+
+void UaFpProcessor::match_mpse(const char* host, const char* uagent, const UaFingerprint*& osfp,
+ const char*& device_info, bool& jail_broken)
+{
+ unsigned len = strlen(uagent);
+ osfp = search_ua_fp(os_mpse, uagent, len);
+
+ auto devicefp = search_ua_fp(device_mpse, uagent, len);
+ if ( devicefp )
+ device_info = devicefp->device.c_str();
+
+ auto jbfp = search_ua_fp(jb_mpse, uagent, len);
+ if ( jbfp and search_ua_fp(jb_host_mpse, host, strlen(host)) )
+ jail_broken = true;
+}
--- /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_fingerprint_ua.h author Masud Hasan <mashasan@cisco.com>
+
+#ifndef RNA_FINGERPRINT_UA_H
+#define RNA_FINGERPRINT_UA_H
+
+#include "main/snort_config.h"
+#include "main/snort_types.h"
+#include "search_engines/search_tool.h"
+
+#include "rna_fingerprint.h"
+
+#define MAX_USER_AGENT_DEVICES 16
+
+namespace snort
+{
+
+class SO_PUBLIC UaFingerprint : public FpFingerprint
+{
+public:
+ std::string user_agent;
+ std::string host_name;
+ std::string device;
+ uint32_t part_num = 0;
+ uint32_t total_parts = 0;
+
+ bool operator==(const UaFingerprint& y) const;
+};
+
+class SO_PUBLIC UaFpProcessor
+{
+public:
+ ~UaFpProcessor();
+
+ void make_mpse(SnortConfig* sc);
+
+ void match_mpse(const char* host, const char* uagent, const UaFingerprint*& osfp,
+ const char*& device_info, bool& jail_broken);
+
+ void push(const RawFingerprint& rfp);
+
+ void push_agent(const UaFingerprint& uafp)
+ { os_fps.emplace_back(uafp); }
+
+ void push_device(const UaFingerprint& uafp)
+ { device_fps.emplace_back(uafp); }
+
+ void push_jb(const UaFingerprint& uafp)
+ { jb_fps.emplace_back(uafp); }
+
+ void push_jb_host(const UaFingerprint& uafp)
+ { jb_host_fps.emplace_back(uafp); }
+
+private:
+ std::vector<UaFingerprint> os_fps;
+ std::vector<UaFingerprint> device_fps;
+ std::vector<UaFingerprint> jb_fps;
+ std::vector<UaFingerprint> jb_host_fps;
+
+ snort::SearchTool* os_mpse = nullptr;
+ snort::SearchTool* device_mpse = nullptr;
+ snort::SearchTool* jb_mpse = nullptr;
+ snort::SearchTool* jb_host_mpse = nullptr;
+};
+
+} // end of namespace snort
+
+snort::UaFpProcessor* get_ua_fp_processor();
+SO_PUBLIC void set_ua_fp_processor(snort::UaFpProcessor*);
+
+#endif
#include "rna_event_handler.h"
#include "rna_fingerprint_tcp.h"
+#include "rna_fingerprint_ua.h"
#include "rna_module.h"
#include "rna_pnd.h"
delete pnd;
delete rna_conf;
if (mod_conf)
- delete mod_conf->processor;
- delete mod_conf;
+ {
+ delete mod_conf->tcp_processor;
+ delete mod_conf->ua_processor;
+ delete mod_conf;
+ }
}
bool RnaInspector::configure(SnortConfig* sc)
void RnaInspector::tinit()
{
// thread local initialization
- set_tcp_fp_processor(mod_conf->processor);
+ set_tcp_fp_processor(mod_conf->tcp_processor);
+ set_ua_fp_processor(mod_conf->ua_processor);
}
void RnaInspector::tterm()
{
if (mod_conf)
{
- if (!mod_conf->processor)
- mod_conf->processor = new TcpFpProcessor;
- return mod_conf->processor;
+ if (!mod_conf->tcp_processor)
+ mod_conf->tcp_processor = new TcpFpProcessor;
+ return mod_conf->tcp_processor;
}
return nullptr;
}
{
if ( mod_conf )
{
- delete mod_conf->processor;
- mod_conf->processor = tfp;
+ delete mod_conf->tcp_processor;
+ mod_conf->tcp_processor = tfp;
}
}
#include "managers/event_manager.h"
#include "protocols/packet.h"
-#include "rna_fingerprint_tcp.h"
+#include "rna_fingerprint.h"
#include "rna_logger_common.h"
#include "rna_module.h"
}
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)
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const FpFingerprint* fp)
{
log(type, subtype, src_ip, src_mac, ht, p, 0, 0,
- nullptr, nullptr, tfp, nullptr, nullptr);
+ nullptr, nullptr, fp, nullptr, nullptr);
}
void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
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,
+ uint16_t proto, const HostMac* hm, const HostApplication* ha, const FpFingerprint* fp,
void* cond_var, const HostClient* hc)
{
if ( !enabled )
assert(ht);
- RnaLoggerEvent rle(type, subtype, src_mac, ht, hm, proto, cond_var, ha, tfp, hc);
+ RnaLoggerEvent rle(type, subtype, src_mac, ht, hm, proto, cond_var, ha, fp, hc);
if ( src_ip and (!IN6_IS_ADDR_V4MAPPED(src_ip) or src_ip->s6_addr32[3]) )
rle.ip = src_ip;
else
{
class Flow;
struct Packet;
-class TcpFingerprint;
+class FpFingerprint;
}
using RnaTracker = std::shared_ptr<snort::HostTracker>;
{
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, const snort::HostClient* hcp) : type(t), subtype(st),
- mac(mc), ht(rt), hm(hmp), proto(pr), cond_var(cv), ha(hap), tfp(tf), hc(hcp) { }
+ const snort::FpFingerprint* fpr, const snort::HostClient* hcp) : type(t), subtype(st),
+ mac(mc), ht(rt), hm(hmp), proto(pr), cond_var(cv), ha(hap), fp(fpr), hc(hcp) { }
uint16_t type;
uint16_t subtype;
uint16_t proto;
void* cond_var;
const snort::HostApplication* ha;
- const snort::TcpFingerprint* tfp;
+ const snort::FpFingerprint* fp;
const snort::HostClient* hc;
};
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::HostClient* hcp);
- // for tcp fingerprint
+ // for 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);
+ const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::FpFingerprint* fp);
// for event time
void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
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,
+ const snort::HostApplication* ha = nullptr, const snort::FpFingerprint* fp = nullptr,
void* cond_var = nullptr, const snort::HostClient* hc = nullptr);
private:
#include "utils/util.h"
#include "rna_fingerprint_tcp.h"
+#include "rna_fingerprint_ua.h"
#include "rna_mac_cache.h"
#ifdef UNIT_TEST
{ nullptr, nullptr, nullptr, nullptr }
};
+static const Parameter user_agent_parts[] =
+{
+ { "substring", Parameter::PT_STRING, nullptr, nullptr, "a substring of user agent string" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
static const Parameter rna_fp_params[] =
{
{ "fpid", Parameter::PT_INT, "0:max32", "0",
{ "df", Parameter::PT_BOOL, nullptr, "false",
"fingerprint don't fragment flag" },
+ { "ua_type", Parameter::PT_ENUM, "os | device | jail-broken | jail-broken-host",
+ "os", "type of user agent fingerprints" },
+
+ { "user_agent", Parameter::PT_LIST, user_agent_parts, nullptr,
+ "list of user agent information parts to match" },
+
+ { "host_name", Parameter::PT_STRING, nullptr, nullptr,
+ "host name information" },
+
+ { "device", Parameter::PT_STRING, nullptr, nullptr,
+ "device information" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
"file name to dump RNA mac cache on shutdown; won't dump by default" },
{ "tcp_fingerprints", Parameter::PT_LIST, rna_fp_params, nullptr,
- "list tcp fingerprints" },
+ "list of tcp fingerprints" },
+
+ { "ua_fingerprints", Parameter::PT_LIST, rna_fp_params, nullptr,
+ "list of user agent fingerprints" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
if (!strcmp(fqn, "rna.tcp_fingerprints"))
{
fingerprint.clear();
- if (!mod_conf->processor)
- mod_conf->processor = new TcpFpProcessor;
+ if (!mod_conf->tcp_processor)
+ mod_conf->tcp_processor = new TcpFpProcessor;
+ }
+ else if (!strcmp(fqn, "rna.ua_fingerprints"))
+ {
+ fingerprint.clear();
+ if (!mod_conf->ua_processor)
+ mod_conf->ua_processor = new UaFpProcessor;
}
return true;
snort_free((void*)dump_file);
dump_file = snort_strdup(v.get_string());
}
-
- else if (fqn && strstr(fqn, "rna.tcp_fingerprints"))
+ else if ( fqn and ( strstr(fqn, "rna.tcp_fingerprints") or
+ strstr(fqn, "rna.ua_fingerprints") ) )
{
if (v.is("fpid"))
fingerprint.fpid = v.get_uint32();
fingerprint.ws = v.get_string();
else if (v.is("df"))
fingerprint.df = v.get_uint8();
+ else if (v.is("ua_type"))
+ fingerprint.ua_type = (UserAgentInfoType)v.get_uint8();
+ else if (v.is("host_name"))
+ fingerprint.host_name = v.get_string();
+ else if (v.is("device"))
+ fingerprint.device = v.get_string();
+ else if (v.is("user_agent"))
+ return true;
+ else if (v.is("substring"))
+ {
+ const auto& ua_part = v.get_string();
+ if ( !ua_part )
+ return false;
+ fingerprint.user_agent.emplace_back(ua_part);
+ }
+ else
+ return false;
}
-
else
return false;
sc->clear_run_flags(RUN_FLAG__IP_FRAGS_ONLY);
}
- if (mod_conf->processor)
+ if ( mod_conf->tcp_processor )
{
- mod_conf->processor->make_tcp_fp_tables(TcpFpProcessor::TCP_FP_MODE::SERVER);
- mod_conf->processor->make_tcp_fp_tables(TcpFpProcessor::TCP_FP_MODE::CLIENT);
+ mod_conf->tcp_processor->make_tcp_fp_tables(TcpFpProcessor::TCP_FP_MODE::SERVER);
+ mod_conf->tcp_processor->make_tcp_fp_tables(TcpFpProcessor::TCP_FP_MODE::CLIENT);
}
+
+ if ( mod_conf->ua_processor )
+ mod_conf->ua_processor->make_mpse(sc);
}
- if ( index > 0 && mod_conf->processor && !strcmp(fqn, "rna.tcp_fingerprints") )
+ if ( index > 0 and mod_conf->tcp_processor and !strcmp(fqn, "rna.tcp_fingerprints") )
{
// there is an implicit conversion here from raw fingerprint (all
// strings) to tcp fingerprint, done by the tcp fingerprint constructor
- mod_conf->processor->push(fingerprint);
+ mod_conf->tcp_processor->push(fingerprint);
+ fingerprint.clear();
+ }
+ else if ( index > 0 and mod_conf->ua_processor and !strcmp(fqn, "rna.ua_fingerprints") )
+ {
+ mod_conf->ua_processor->push(fingerprint);
fingerprint.clear();
}
bool RnaModule::is_valid_fqn(const char* fqn) const
{
- return !strcmp(fqn, RNA_NAME) || !strcmp(fqn, "rna.tcp_fingerprints");
+ return !strcmp(fqn, RNA_NAME) or !strcmp(fqn, "rna.tcp_fingerprints") or
+ !strcmp(fqn, "rna.ua_fingerprints") or !strcmp(fqn, "rna.ua_fingerprints.user_agent");
}
TcpFingerprint::TcpFingerprint(const RawFingerprint&) { }
bool TcpFingerprint::operator==(const TcpFingerprint&) const { return true; }
+UaFpProcessor::~UaFpProcessor() { }
+void UaFpProcessor::make_mpse(SnortConfig*) { }
+void UaFpProcessor::push(RawFingerprint const&) { }
+
// inspector
class RnaInspector
{
{
if (mod_conf)
{
- if (mod_conf->processor)
- delete mod_conf->processor;
- delete mod_conf;
- }
+ delete mod_conf->tcp_processor;
+ delete mod_conf->ua_processor;
+ delete mod_conf;
+ }
}
TcpFpProcessor* get_fp_processor()
{
- return mod_conf->processor;
+ return mod_conf->tcp_processor;
}
private: