if( (appHA->flags & APPID_HA_FLAGS_TP_DONE) && asd->tpsession )
{
#ifdef ENABLE_APPID_THIRD_PARTY
- if( asd->tpsession)
- asd->tpsession->set_state(TP_STATE_TERMINATED);
+ asd->tpsession->set_state(TP_STATE_TERMINATED);
#endif
asd->set_session_flags(APPID_SESSION_NO_TPI);
}
my_version.clear();
}
- virtual void update(AppId id, char* vendor, char* version)
+ virtual void update(AppId id, char* vendor, char* version, AppidChangeBits& change_bits)
{
set_id(id);
set_vendor(vendor);
- set_version(version);
+ set_version(version, change_bits);
}
virtual void update_stats(AppId id) = 0;
return my_version.empty() ? nullptr : my_version.c_str();
}
- void set_version(const char* version)
+ void set_version(const char* version, AppidChangeBits& change_bits)
{
if ( version )
+ {
my_version = version;
+ change_bits.set(APPID_VERSION_BIT);
+ }
}
private:
return asd.add_flow_data(data, flow_data_index, fcn);
}
-void AppIdDetector::add_info(AppIdSession& asd, const char* info)
+void AppIdDetector::add_info(AppIdSession& asd, const char* info, AppidChangeBits& change_bits)
{
AppIdHttpSession* hsession = asd.get_http_session();
if ( !hsession->get_field(MISC_URL_FID) )
- hsession->set_field(MISC_URL_FID, new std::string(info));
+ hsession->set_field(MISC_URL_FID, new std::string(info), change_bits);
}
void AppIdDetector::add_user(AppIdSession& asd, const char* username, AppId appId, bool success)
}
void AppIdDetector::add_app(AppIdSession& asd, AppId service_id, AppId client_id,
- const char* version)
+ const char* version, AppidChangeBits& change_bits)
{
if ( version )
- asd.client.set_version(version);
+ asd.client.set_version(version, change_bits);
asd.set_client_detected();
asd.client_inferred_service_id = service_id;
class AppIdDiscoveryArgs
{
public:
- AppIdDiscoveryArgs(const uint8_t* data, uint16_t size, AppidSessionDirection dir, AppIdSession& asd,
- snort::Packet* p) : data(data), size(size), dir(dir), asd(asd), pkt(p), config(asd.config)
+ AppIdDiscoveryArgs(const uint8_t* data, uint16_t size, AppidSessionDirection dir,
+ AppIdSession& asd, snort::Packet* p, AppidChangeBits& cb) : data(data),
+ size(size), dir(dir), asd(asd), pkt(p), config(asd.config), change_bits(cb)
{}
const uint8_t* data;
AppIdSession& asd;
snort::Packet* pkt;
const AppIdConfig* config = nullptr;
+ AppidChangeBits& change_bits;
};
// These numbers are what Lua (VDB/ODP) gives us. If these numbers are ever changed,
virtual void* data_get(AppIdSession&);
virtual int data_add(AppIdSession&, void*, AppIdFreeFCN);
- virtual void add_info(AppIdSession&, const char*);
+ virtual void add_info(AppIdSession&, const char*, AppidChangeBits&);
virtual void add_user(AppIdSession&, const char*, AppId, bool);
virtual void add_payload(AppIdSession&, AppId);
- virtual void add_app(AppIdSession&, AppId, AppId, const char*);
+ virtual void add_app(AppIdSession&, AppId, AppId, const char*, AppidChangeBits&);
virtual void finalize_patterns() {}
const char* get_code_string(APPID_STATUS_CODE) const;
return;
AppId service_id;
- bool is_discovery_done = do_discovery(p, *asd, protocol, direction, service_id);
+ AppidChangeBits change_bits;
+ bool is_discovery_done = do_discovery(p, *asd, protocol, direction, service_id, change_bits);
- do_post_discovery(p, *asd, direction, is_discovery_done, service_id);
+ do_post_discovery(p, *asd, direction, is_discovery_done, service_id, change_bits);
+}
+
+void AppIdDiscovery::publish_appid_event(AppidChangeBits& change_bits, snort::Flow* flow)
+{
+ if (change_bits.none())
+ return;
+
+ AppidEvent app_event(change_bits);
+ DataBus::publish(APPID_EVENT_ANY_CHANGE, app_event, flow);
+ if (appidDebug->is_active())
+ {
+ std::string str;
+ change_bits_to_string(change_bits, str);
+ LogMessage("AppIdDbg %s Published event for changes: %s\n",
+ appidDebug->get_debug_session(), str.c_str());
+ }
}
static inline int match_pe_network(const SfIp* pktAddr, const PortExclusion* pe)
{
if (!asd->get_session_flags(APPID_SESSION_IGNORE_FLOW_IDED))
{
+ AppidChangeBits change_bits;
asd->set_application_ids(asd->pick_service_app_id(), asd->pick_client_app_id(),
- asd->pick_payload_app_id(), asd->pick_misc_app_id());
+ asd->pick_payload_app_id(), asd->pick_misc_app_id(), change_bits);
+ publish_appid_event(change_bits, p->flow);
asd->set_session_flags(APPID_SESSION_IGNORE_FLOW_IDED);
}
}
bool AppIdDiscovery::do_discovery(Packet* p, AppIdSession& asd, IpProtocol protocol,
- AppidSessionDirection direction, AppId& service_id)
+ AppidSessionDirection direction, AppId& service_id, AppidChangeBits& change_bits)
{
bool is_discovery_done = false;
if ( !(asd.scan_flags & SCAN_HOST_PORT_FLAG) )
lookup_appid_by_host_port(asd, p, protocol, direction);
- asd.check_app_detection_restart();
+ asd.check_app_detection_restart(change_bits);
// Third party detection
#ifdef ENABLE_APPID_THIRD_PARTY
if ( TPLibHandler::have_tp() )
- is_discovery_done = do_tp_discovery(asd,protocol,p,direction);
+ is_discovery_done = do_tp_discovery(asd, protocol, p, direction, change_bits);
#endif
// Port-based service detection
// exceptions for rexec and any other service detector that need to see SYN and SYN/ACK
if (asd.get_session_flags(APPID_SESSION_REXEC_STDERR))
{
- ServiceDiscovery::get_instance().identify_service(asd, p, direction);
+ ServiceDiscovery::get_instance().identify_service(asd, p, direction, change_bits);
AppIdDnsSession* dsession = asd.get_dns_session();
if (asd.service.get_id() == APP_ID_DNS &&
AppId client_id = APP_ID_NONE, payload_id = APP_ID_NONE;
dns_host_scan_hostname((const uint8_t*)dsession->get_host(), dsession->get_host_len(),
&client_id, &payload_id);
- asd.set_client_appid_data(client_id, nullptr);
+ asd.set_client_appid_data(client_id, nullptr, change_bits);
}
else if (asd.service.get_id() == APP_ID_RTMP)
- asd.examine_rtmp_metadata();
+ asd.examine_rtmp_metadata(change_bits);
else if (asd.get_session_flags(APPID_SESSION_SSL_SESSION) && asd.tsession)
- asd.examine_ssl_metadata(p);
+ asd.examine_ssl_metadata(p, change_bits);
}
// FIXIT-M - snort 2.x has added a check for midstream pickup to this, do we need that?
else if (protocol != IpProtocol::TCP || (p->packet_flags & PKT_STREAM_ORDER_OK))
{
if (asd.service_disco_state != APPID_DISCO_STATE_FINISHED)
- is_discovery_done =
- ServiceDiscovery::get_instance().do_service_discovery(asd, p, direction);
+ is_discovery_done = ServiceDiscovery::get_instance().do_service_discovery(asd, p,
+ direction, change_bits);
if (asd.client_disco_state != APPID_DISCO_STATE_FINISHED)
- is_discovery_done =
- ClientDiscovery::get_instance().do_client_discovery(asd, p, direction);
+ is_discovery_done = ClientDiscovery::get_instance().do_client_discovery(asd, p,
+ direction, change_bits);
asd.set_session_flags(APPID_SESSION_ADDITIONAL_PACKET);
}
}
void AppIdDiscovery::do_post_discovery(Packet* p, AppIdSession& asd,
- AppidSessionDirection direction, bool is_discovery_done, AppId service_id)
+ AppidSessionDirection direction, bool is_discovery_done, AppId service_id,
+ AppidChangeBits& change_bits)
{
AppId payload_id = asd.pick_payload_app_id();
}
asd.set_application_ids(service_id, asd.pick_client_app_id(), payload_id,
- asd.pick_misc_app_id());
+ asd.pick_misc_app_id(), change_bits);
// Set the field that the Firewall queries to see if we have a search engine
if (asd.search_support_type == UNKNOWN_SEARCH_ENGINE && payload_id > APP_ID_NONE)
asd.past_forecast = check_session_for_AF_forecast(asd, p, direction,
(AppId)service_id);
asd.set_application_ids(service_id, asd.pick_client_app_id(),
- asd.pick_payload_app_id(), asd.pick_misc_app_id());
+ asd.pick_payload_app_id(), asd.pick_misc_app_id(), change_bits);
}
}
+
+ publish_appid_event(change_bits, p->flow);
}
#include <string>
#include <vector>
-#include "appid_types.h"
-#include "application_ids.h"
-
+#include "flow/flow.h"
#include "protocols/protocol_ids.h"
+#include "pub_sub/appid_events.h"
#include "search_engines/search_tool.h"
-#include "flow/flow.h"
#include "utils/util.h"
+#include "appid_types.h"
+#include "application_ids.h"
+
class AppIdInspector;
class AppIdSession;
class AppIdDetector;
virtual int add_service_port(AppIdDetector*, const ServiceDetectorPort&);
static void do_application_discovery(snort::Packet* p, AppIdInspector&);
+ static void publish_appid_event(AppidChangeBits&, snort::Flow*);
AppIdDetectors* get_tcp_detectors()
{
static bool do_pre_discovery(snort::Packet* p, AppIdSession** p_asd, AppIdInspector& inspector,
IpProtocol& protocol, AppidSessionDirection& direction);
static bool do_discovery(snort::Packet* p, AppIdSession& asd, IpProtocol protocol,
- AppidSessionDirection direction, AppId& service_id);
+ AppidSessionDirection direction, AppId& service_id, AppidChangeBits& change_bits);
static void do_post_discovery(snort::Packet* p, AppIdSession& asd,
- AppidSessionDirection direction, bool is_discovery_done, AppId service_id);
+ AppidSessionDirection direction, bool is_discovery_done, AppId service_id,
+ AppidChangeBits& change_bits);
static bool handle_unmonitored_session(AppIdSession* asd, const snort::Packet* p,
IpProtocol protocol, AppidSessionDirection dir, AppIdInspector& inspector,
uint64_t& flow_flags);
#include "app_info_table.h"
#include "appid_debug.h"
+#include "appid_discovery.h"
#include "appid_http_session.h"
#include "appid_session.h"
#include "utils/util.h"
void HttpEventHandler::handle(DataEvent& event, Flow* flow)
{
- AppidSessionDirection direction;
- const uint8_t* header_start;
- int32_t header_length;
- HttpEvent* http_event = (HttpEvent*)&event;
-
assert(flow);
AppIdSession* asd = appid_api.get_appid_session(*flow);
if (!asd)
return;
+ AppidSessionDirection direction;
+ const uint8_t* header_start;
+ int32_t header_length;
+ HttpEvent* http_event = (HttpEvent*)&event;
+ AppidChangeBits change_bits;
+
if (appidDebug->is_active())
LogMessage("AppIdDbg %s Processing HTTP metadata from HTTP Inspector\n",
appidDebug->get_debug_session());
header_start = http_event->get_host(header_length);
if (header_length > 0)
{
- hsession->set_field(REQ_HOST_FID, header_start, header_length);
+ hsession->set_field(REQ_HOST_FID, header_start, header_length, change_bits);
asd->scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
header_start = http_event->get_uri(header_length);
if (header_length > 0)
{
- hsession->set_field(REQ_URI_FID, header_start, header_length);
- hsession->update_url();
+ hsession->set_field(REQ_URI_FID, header_start, header_length, change_bits);
+ hsession->update_url(change_bits);
}
}
header_start = http_event->get_user_agent(header_length);
if (header_length > 0)
{
- hsession->set_field(REQ_AGENT_FID, header_start, header_length);
+ hsession->set_field(REQ_AGENT_FID, header_start, header_length, change_bits);
asd->scan_flags |= SCAN_HTTP_USER_AGENT_FLAG;
}
header_start = http_event->get_cookie(header_length);
- hsession->set_field(REQ_COOKIE_FID, header_start, header_length);
+ hsession->set_field(REQ_COOKIE_FID, header_start, header_length, change_bits);
header_start = http_event->get_referer(header_length);
- hsession->set_field(REQ_REFERER_FID, header_start, header_length);
+ hsession->set_field(REQ_REFERER_FID, header_start, header_length, change_bits);
header_start = http_event->get_x_working_with(header_length);
- hsession->set_field(MISC_XWW_FID, header_start, header_length);
+ hsession->set_field(MISC_XWW_FID, header_start, header_length, change_bits);
hsession->set_is_webdav(http_event->contains_webdav_method());
// FIXIT-M: Should we get request body (may be expensive to copy)?
else // Response headers.
{
header_start = http_event->get_content_type(header_length);
- hsession->set_field(RSP_CONTENT_TYPE_FID, header_start, header_length);
+ hsession->set_field(RSP_CONTENT_TYPE_FID, header_start, header_length, change_bits);
header_start = http_event->get_location(header_length);
- hsession->set_field(RSP_LOCATION_FID, header_start, header_length);
+ hsession->set_field(RSP_LOCATION_FID, header_start, header_length, change_bits);
header_start = http_event->get_server(header_length);
- hsession->set_field(MISC_SERVER_FID, header_start, header_length);
+ hsession->set_field(MISC_SERVER_FID, header_start, header_length, change_bits);
int32_t responseCodeNum = http_event->get_response_code();
if (responseCodeNum > 0 && responseCodeNum < 700)
char tmpstr[32];
ret = snprintf(tmpstr, sizeof(tmpstr), "%d", responseCodeNum);
if ( ret < sizeof(tmpstr) )
- hsession->set_field(MISC_RESP_CODE_FID, (const uint8_t*)tmpstr, ret);
+ hsession->set_field(MISC_RESP_CODE_FID, (const uint8_t*)tmpstr, ret, change_bits);
}
// FIXIT-M: Get Location header data.
header_start = http_event->get_via(header_length);
if (header_length > 0)
{
- hsession->set_field(MISC_VIA_FID, header_start, header_length);
+ hsession->set_field(MISC_VIA_FID, header_start, header_length, change_bits);
asd->scan_flags |= SCAN_HTTP_VIA_FLAG;
}
- hsession->process_http_packet(direction);
+ hsession->process_http_packet(direction, change_bits);
if (asd->service.get_id() == APP_ID_HTTP)
{
asd->set_application_ids(asd->pick_service_app_id(), asd->pick_client_app_id(),
- asd->pick_payload_app_id(), asd->pick_misc_app_id());
+ asd->pick_payload_app_id(), asd->pick_misc_app_id(), change_bits);
}
+
+ AppIdDiscovery::publish_appid_event(change_bits, flow);
}
cmd.chp_matches[i].clear();
}
+void AppIdHttpSession::set_http_change_bits(AppidChangeBits& change_bits, HttpFieldIds id)
+{
+ switch (id)
+ {
+ case REQ_HOST_FID:
+ change_bits.set(APPID_HOST_BIT);
+ break;
+ case MISC_URL_FID:
+ change_bits.set(APPID_URL_BIT);
+ break;
+ case REQ_AGENT_FID:
+ change_bits.set(APPID_USERAGENT_BIT);
+ break;
+ case MISC_RESP_CODE_FID:
+ change_bits.set(APPID_RESPONSE_BIT);
+ break;
+ case REQ_REFERER_FID:
+ change_bits.set(APPID_REFERER_BIT);
+ break;
+ default:
+ break;
+ }
+}
+
int AppIdHttpSession::initial_chp_sweep(ChpMatchDescriptor& cmd)
{
CHPApp* cah = nullptr;
}
}
-void AppIdHttpSession::process_chp_buffers()
+void AppIdHttpSession::process_chp_buffers(AppidChangeBits& change_bits)
{
ChpMatchDescriptor cmd;
: CHP_APPIDINSTANCE_TO_ID(chp_candidate);
if (app_type_flags & APP_TYPE_SERVICE)
- asd.set_service_appid_data(chp_final, nullptr, version);
+ asd.set_service_appid_data(chp_final, nullptr, version, change_bits);
if (app_type_flags & APP_TYPE_CLIENT)
- asd.set_client_appid_data(chp_final, version);
+ asd.set_client_appid_data(chp_final, version, change_bits);
if ( app_type_flags & APP_TYPE_PAYLOAD )
- asd.set_payload_appid_data((AppId)chp_final, version);
+ asd.set_payload_appid_data((AppId)chp_final, version, change_bits);
if ( version )
{
httpFieldName[i], cmd.chp_rewritten[i]);
set_field((HttpFieldIds)i, (const uint8_t*)cmd.chp_rewritten[i],
- strlen(cmd.chp_rewritten[i]));
+ strlen(cmd.chp_rewritten[i]), change_bits);
delete [] cmd.chp_rewritten[i];
cmd.chp_rewritten[i] = nullptr;
}
}
}
-int AppIdHttpSession::process_http_packet(AppidSessionDirection direction)
+int AppIdHttpSession::process_http_packet(AppidSessionDirection direction,
+ AppidChangeBits& change_bits)
{
snort::Profile http_profile_context(httpPerfStats);
AppId service_id = APP_ID_NONE;
}
if (!chp_finished || chp_hold_flow)
- process_chp_buffers();
+ process_chp_buffers(change_bits);
if (!skip_simple_detect) // true if processCHP found match
{
if (vendor || vendorVersion)
{
asd.service.set_vendor(vendor);
- asd.service.set_version(vendorVersion);
+ asd.service.set_version(vendorVersion, change_bits);
asd.scan_flags &= ~SCAN_HTTP_VENDOR_FLAG;
snort_free(vendor);
{
if (appidDebug->is_active() and asd.payload.get_id() != APP_ID_WEBDAV)
LogMessage("AppIdDbg %s Data is webdav\n", appidDebug->get_debug_session());
- asd.set_payload_appid_data(APP_ID_WEBDAV, nullptr);
+ asd.set_payload_appid_data(APP_ID_WEBDAV, nullptr, change_bits);
}
// Scan User-Agent for Browser types or Skype
appidDebug->get_debug_session(), app_name ? app_name : "unknown", client_id);
}
}
- asd.set_service_appid_data(service_id, nullptr, nullptr);
- asd.set_client_appid_data(client_id, version);
+ asd.set_service_appid_data(service_id, nullptr, nullptr, change_bits);
+ asd.set_client_appid_data(client_id, version, change_bits);
asd.scan_flags &= ~SCAN_HTTP_USER_AGENT_FLAG;
snort_free(version);
}
app_name ? app_name : "unknown",
payload_id);
}
- asd.set_payload_appid_data((AppId)payload_id, nullptr);
+ asd.set_payload_appid_data((AppId)payload_id, nullptr, change_bits);
asd.scan_flags &= ~SCAN_HTTP_VIA_FLAG;
}
}
LogMessage("AppIdDbg %s X is client %s (%d)\n", appidDebug->get_debug_session(),
app_name ? app_name : "unknown", appId);
}
- asd.set_client_appid_data(appId, version);
+ asd.set_client_appid_data(appId, version, change_bits);
}
else
{
LogMessage("AppIdDbg %s X service %s (%d)\n", appidDebug->get_debug_session(),
app_name ? app_name : "unknown", appId);
}
- asd.set_service_appid_data(appId, nullptr, version);
+ asd.set_service_appid_data(appId, nullptr, version, change_bits);
}
asd.scan_flags &= ~SCAN_HTTP_XWORKINGWITH_FLAG;
}
app_name ? app_name : "unknown",
payload_id);
}
- asd.set_payload_appid_data((AppId)payload_id, nullptr);
+ asd.set_payload_appid_data((AppId)payload_id, nullptr, change_bits);
asd.scan_flags &= ~SCAN_HTTP_CONTENT_TYPE_FLAG;
}
app_name ? app_name : "unknown",
client_id);
}
- asd.set_client_appid_data(client_id, nullptr);
+ asd.set_client_appid_data(client_id, nullptr, change_bits);
}
if (asd.service.get_id() <= APP_ID_NONE)
app_name ? app_name : "unknown",
service_id);
}
- asd.set_service_appid_data(service_id, nullptr, nullptr);
+ asd.set_service_appid_data(service_id, nullptr, nullptr, change_bits);
}
// DO overwrite a previously-set data
app_name ? app_name : "unknown",
payload_id);
}
- asd.set_payload_appid_data((AppId)payload_id, version);
- asd.set_referred_payload_app_id_data(referredPayloadAppId);
+ asd.set_payload_appid_data((AppId)payload_id, version, change_bits);
+ asd.set_referred_payload_app_id_data(referredPayloadAppId, change_bits);
}
asd.scan_flags &= ~SCAN_HTTP_HOST_URL_FLAG;
// FIXIT-H - Implement this function when (reconfigurable) XFF is supported.
void AppIdHttpSession::update_http_xff_address(struct XffFieldValue* xff_fields,
- uint32_t numXffFields)
+ uint32_t numXffFields, AppidChangeBits& change_bits)
{
UNUSED(xff_fields);
UNUSED(numXffFields);
+ UNUSED(change_bits);
#if 0
+ // When this is implemented, do change_bits.set(APPID_XFF_BIT) soon after xff_addr is changed
static const char* defaultXffPrecedence[] =
{
HTTP_XFF_FIELD_X_FORWARDED_FOR,
#endif
}
-void AppIdHttpSession::update_url()
+void AppIdHttpSession::update_url(AppidChangeBits& change_bits)
{
const std::string* host = meta_data[REQ_HOST_FID];
const std::string* uri = meta_data[REQ_URI_FID];
if (meta_data[MISC_URL_FID])
delete meta_data[MISC_URL_FID];
meta_data[MISC_URL_FID] = new std::string(std::string("http://") + *host + *uri);
+ change_bits.set(APPID_URL_BIT);
}
}
#include <utility>
#include "flow/flow.h"
+#include "pub_sub/appid_events.h"
#include "sfip/sf_ip.h"
#include "appid_types.h"
AppIdHttpSession(AppIdSession&);
virtual ~AppIdHttpSession();
- int process_http_packet(AppidSessionDirection direction);
- void update_http_xff_address(struct XffFieldValue* xff_fields, uint32_t numXffFields);
+ int process_http_packet(AppidSessionDirection direction, AppidChangeBits& change_bits);
+ void update_http_xff_address(struct XffFieldValue*, uint32_t, AppidChangeBits&);
- void update_url();
+ void update_url(AppidChangeBits& change_bits);
snort::SfIp* get_xff_addr()
{ return xff_addr; }
const char* get_cfield(HttpFieldIds id)
{ return meta_data[id] != nullptr ? meta_data[id]->c_str() : nullptr; }
- void set_field(HttpFieldIds id, const std::string* str)
+ void set_field(HttpFieldIds id, const std::string* str, AppidChangeBits& change_bits)
{
delete meta_data[id];
meta_data[id] = str;
+ if (str)
+ set_http_change_bits(change_bits, id);
}
- void set_field(HttpFieldIds id, const uint8_t* str, int32_t len)
+ void set_field(HttpFieldIds id, const uint8_t* str, int32_t len, AppidChangeBits& change_bits)
{
delete meta_data[id];
- meta_data[id] = str and len ? new std::string((const char*)str, len) : nullptr;
+ if (str and len)
+ {
+ meta_data[id] = new std::string((const char*)str, len);
+ set_http_change_bits(change_bits, id);
+ }
+ else
+ meta_data[id] = nullptr;
}
bool get_offset(int id, uint16_t& start, uint16_t& end)
void init_chp_match_descriptor(ChpMatchDescriptor& cmd);
int initial_chp_sweep(ChpMatchDescriptor&);
- void process_chp_buffers();
+ void process_chp_buffers(AppidChangeBits&);
void free_chp_matches(ChpMatchDescriptor& cmd, unsigned max_matches);
+ void set_http_change_bits(AppidChangeBits& change_bits, HttpFieldIds id);
HttpPatternMatchers* http_matchers = nullptr;
length_sequence.proto = IpProtocol::PROTO_NOT_SET;
length_sequence.sequence_cnt = 0;
memset(length_sequence.sequence, '\0', sizeof(length_sequence.sequence));
-
+ memset(application_ids, 0, sizeof(application_ids));
appid_stats.total_sessions++;
}
return asd;
}
-void AppIdSession::reinit_session_data()
+void AppIdSession::reinit_session_data(AppidChangeBits& change_bits)
{
misc_app_id = APP_ID_NONE;
referred_payload_app_id = tp_payload_app_id = APP_ID_NONE;
clear_session_flags(APPID_SESSION_CONTINUE);
if ( hsession )
- hsession->set_field(MISC_URL_FID, nullptr);
+ hsession->set_field(MISC_URL_FID, nullptr, change_bits);
}
//service
}
}
-void AppIdSession::check_app_detection_restart()
+void AppIdSession::check_app_detection_restart(AppidChangeBits& change_bits)
{
if (get_session_flags(APPID_SESSION_DECRYPTED) || !flow->is_proxied())
return;
encrypted.client_id = pick_client_app_id();
encrypted.misc_id = pick_misc_app_id();
encrypted.referred_id = pick_referred_payload_app_id();
- reinit_session_data();
+ reinit_session_data(change_bits);
if (appidDebug->is_active())
LogMessage("AppIdDbg %s SSL decryption is available, restarting app detection\n",
appidDebug->get_debug_session());
}
}
-void AppIdSession::examine_ssl_metadata(Packet* p)
+void AppIdSession::examine_ssl_metadata(Packet* p, AppidChangeBits& change_bits)
{
int ret;
AppId client_id = 0;
AppId payload_id = 0;
+ const char* tls_str = tsession->get_tls_host();
- if ((scan_flags & SCAN_SSL_HOST_FLAG) && tsession->tls_host)
+ if ((scan_flags & SCAN_SSL_HOST_FLAG) and tls_str)
{
- size_t size = strlen(tsession->tls_host);
- if ((ret = ssl_scan_hostname((const uint8_t*)tsession->tls_host, size,
+ size_t size = strlen(tls_str);
+ if ((ret = ssl_scan_hostname((const uint8_t*)tls_str, size,
&client_id, &payload_id)))
{
- set_client_appid_data(client_id, nullptr);
- set_payload_appid_data((AppId)payload_id, nullptr);
+ set_client_appid_data(client_id, nullptr, change_bits);
+ set_payload_appid_data((AppId)payload_id, nullptr, change_bits);
setSSLSquelch(p, ret, (ret == 1 ? payload_id : client_id), inspector);
}
scan_flags &= ~SCAN_SSL_HOST_FLAG;
}
- if (tsession->tls_cname)
+ if ((tls_str = tsession->get_tls_cname()))
{
- size_t size = strlen(tsession->tls_cname);
- if ((ret = ssl_scan_cname((const uint8_t*)tsession->tls_cname, size,
+ size_t size = strlen(tls_str);
+ if ((ret = ssl_scan_cname((const uint8_t*)tls_str, size,
&client_id, &payload_id)))
{
- set_client_appid_data(client_id, nullptr);
- set_payload_appid_data((AppId)payload_id, nullptr);
+ set_client_appid_data(client_id, nullptr, change_bits);
+ set_payload_appid_data((AppId)payload_id, nullptr, change_bits);
setSSLSquelch(p, ret, (ret == 1 ? payload_id : client_id), inspector);
}
- snort_free(tsession->tls_cname);
- tsession->tls_cname = nullptr;
+ tsession->set_tls_cname(nullptr, 0);
}
- if (tsession->tls_orgUnit)
+ if ((tls_str = tsession->get_tls_org_unit()))
{
- size_t size = strlen(tsession->tls_orgUnit);
- if ((ret = ssl_scan_cname((const uint8_t*)tsession->tls_orgUnit, size,
+ size_t size = strlen(tls_str);
+ if ((ret = ssl_scan_cname((const uint8_t*)tls_str, size,
&client_id, &payload_id)))
{
- set_client_appid_data(client_id, nullptr);
- set_payload_appid_data((AppId)payload_id, nullptr);
+ set_client_appid_data(client_id, nullptr, change_bits);
+ set_payload_appid_data((AppId)payload_id, nullptr, change_bits);
setSSLSquelch(p, ret, (ret == 1 ? payload_id : client_id), inspector);
}
- snort_free(tsession->tls_orgUnit);
- tsession->tls_orgUnit = nullptr;
+ tsession->set_tls_org_unit(nullptr, 0);
}
}
-void AppIdSession::examine_rtmp_metadata()
+void AppIdSession::examine_rtmp_metadata(AppidChangeBits& change_bits)
{
AppId service_id = APP_ID_NONE;
AppId client_id = APP_ID_NONE;
{
/* do not overwrite a previously-set client or service */
if (client.get_id() <= APP_ID_NONE)
- set_client_appid_data(payload_id, nullptr);
+ set_client_appid_data(payload_id, nullptr, change_bits);
if (service.get_id() <= APP_ID_NONE)
- set_service_appid_data(service_id, nullptr, nullptr);
+ set_service_appid_data(service_id, nullptr, nullptr, change_bits);
/* DO overwrite a previously-set data */
- set_payload_appid_data((AppId)payload.get_id(), nullptr);
- set_referred_payload_app_id_data(referred_payload_id);
+ set_payload_appid_data((AppId)payload.get_id(), nullptr, change_bits);
+ set_referred_payload_app_id_data(referred_payload_id, change_bits);
}
}
}
-void AppIdSession::set_client_appid_data(AppId id, char* version)
+void AppIdSession::set_client_appid_data(AppId id, char* version, AppidChangeBits& change_bits)
{
if ( id <= APP_ID_NONE || id == APP_ID_HTTP )
return;
client.set_id(id);
}
- client.set_version(version);
+ client.set_version(version, change_bits);
}
-void AppIdSession::set_referred_payload_app_id_data(AppId id)
+void AppIdSession::set_referred_payload_app_id_data(AppId id, AppidChangeBits& change_bits)
{
if (id <= APP_ID_NONE)
return;
if (referred_payload_app_id != id)
+ {
referred_payload_app_id = id;
+ change_bits.set(APPID_REFERRED_BIT);
+ }
}
-void AppIdSession::set_payload_appid_data(AppId id, char* version)
+void AppIdSession::set_payload_appid_data(AppId id, char* version, AppidChangeBits& change_bits)
{
if ( id <= APP_ID_NONE )
return;
if ( app_info_mgr->get_priority(payload.get_id()) > app_info_mgr->get_priority(id) )
return;
payload.set_id(id);
- payload.set_version(version);
+ payload.set_version(version, change_bits);
}
-void AppIdSession::set_service_appid_data(AppId id, char* vendor, char* version)
+void AppIdSession::set_service_appid_data(AppId id, char* vendor, char* version,
+ AppidChangeBits& change_bits)
{
if (id <= APP_ID_NONE)
return;
return;
}
- service.update(id, vendor, version);
+ service.update(id, vendor, version, change_bits);
}
void AppIdSession::free_tls_session_data()
{
if ( tsession )
{
- if (tsession->tls_host)
- snort_free(tsession->tls_host);
- if (tsession->tls_cname)
- snort_free(tsession->tls_cname);
- if (tsession->tls_orgUnit)
- snort_free(tsession->tls_orgUnit);
+ tsession->free_data();
snort_free(tsession);
tsession = nullptr;
}
}
void AppIdSession::set_application_ids(AppId service_id, AppId client_id,
- AppId payload_id, AppId misc_id)
+ AppId payload_id, AppId misc_id, AppidChangeBits& change_bits)
{
- application_ids[APP_PROTOID_SERVICE] = service_id;
- application_ids[APP_PROTOID_CLIENT] = client_id;
- application_ids[APP_PROTOID_PAYLOAD] = payload_id;
- application_ids[APP_PROTOID_MISC] = misc_id;
+ if (application_ids[APP_PROTOID_SERVICE] != service_id)
+ {
+ application_ids[APP_PROTOID_SERVICE] = service_id;
+ change_bits.set(APPID_SERVICE_BIT);
+ }
+ if (application_ids[APP_PROTOID_CLIENT] != client_id)
+ {
+ application_ids[APP_PROTOID_CLIENT] = client_id;
+ change_bits.set(APPID_CLIENT_BIT);
+ }
+ if (application_ids[APP_PROTOID_PAYLOAD] != payload_id)
+ {
+ application_ids[APP_PROTOID_PAYLOAD] = payload_id;
+ change_bits.set(APPID_PAYLOAD_BIT);
+ }
+ if (application_ids[APP_PROTOID_MISC] != misc_id)
+ {
+ application_ids[APP_PROTOID_MISC] = misc_id;
+ change_bits.set(APPID_MISC_BIT);
+ }
}
void AppIdSession::get_application_ids(AppId& service_id, AppId& client_id,
#include <string>
#include <unordered_map>
-#include "detector_plugins/http_url_patterns.h"
+#include "pub_sub/appid_events.h"
+
#include "app_info_table.h"
#include "appid_api.h"
#include "appid_app_descriptor.h"
#include "appid_types.h"
#include "application_ids.h"
+#include "detector_plugins/http_url_patterns.h"
#include "length_app_cache.h"
#include "service_state.h"
// FIXIT-L: make these const strings
struct TlsSession
{
- char* tls_host = nullptr;
- int tls_host_strlen = 0; // FIXIT-M: not rvalue, remove
- char* tls_cname = nullptr;
- int tls_cname_strlen = 0; // FIXIT-M: not rvalue, remove
- char* tls_orgUnit = nullptr;
- int tls_orgUnit_strlen = 0; // FIXiT-M: not rvalue, remove
+ char* get_tls_host() { return tls_host; }
+
+ char* get_tls_cname() { return tls_cname; }
- void set_tls_host(const char* new_tls_host, uint32_t len)
+ char* get_tls_org_unit() { return tls_org_unit; }
+
+ // Duplicate only if len > 0, otherwise simply set (i.e., own the argument)
+ void set_tls_host(const char* new_tls_host, uint32_t len, AppidChangeBits& change_bits)
{
- if (tls_host) snort_free(tls_host);
- tls_host = snort::snort_strndup(new_tls_host,len);
- tls_host_strlen = len;
+ if (tls_host)
+ snort_free(tls_host);
+ if (!new_tls_host)
+ {
+ tls_host = nullptr;
+ return;
+ }
+ tls_host = len? snort::snort_strndup(new_tls_host,len) : const_cast<char*>(new_tls_host);
+ change_bits.set(APPID_TLSHOST_BIT);
}
void set_tls_cname(const char* new_tls_cname, uint32_t len)
{
- if (tls_cname) snort_free(tls_cname);
- tls_cname = snort::snort_strndup(new_tls_cname,len);
- tls_cname_strlen = len;
+ if (tls_cname)
+ snort_free(tls_cname);
+ tls_cname = len? snort::snort_strndup(new_tls_cname,len) :
+ const_cast<char*>(new_tls_cname);
}
void set_tls_org_unit(const char* new_tls_org_unit, uint32_t len)
{
- if (tls_orgUnit) snort_free(tls_orgUnit);
- tls_orgUnit = snort::snort_strndup(new_tls_org_unit,len);
- tls_orgUnit_strlen = len;
+ if (tls_org_unit)
+ snort_free(tls_org_unit);
+ tls_org_unit = len? snort::snort_strndup(new_tls_org_unit,len) :
+ const_cast<char*>(new_tls_org_unit);
}
+
+ void free_data()
+ {
+ if (tls_host)
+ snort_free(tls_host);
+ if (tls_cname)
+ snort_free(tls_cname);
+ if (tls_org_unit)
+ snort_free(tls_org_unit);
+ tls_host = tls_cname = tls_org_unit = nullptr;
+ }
+
+private:
+ char* tls_host = nullptr;
+ char* tls_cname = nullptr;
+ char* tls_org_unit = nullptr;
};
class AppIdSession : public snort::FlowData
AppId pick_client_app_id();
AppId pick_payload_app_id();
AppId pick_referred_payload_app_id();
- void set_application_ids(AppId service, AppId client, AppId payload, AppId misc);
+ void set_application_ids(AppId service, AppId client, AppId payload, AppId misc,
+ AppidChangeBits& change_bits);
void get_application_ids(AppId& service, AppId& client, AppId& payload, AppId& misc);
void get_application_ids(AppId& service, AppId& client, AppId& payload);
AppId get_application_ids_service();
AppId get_application_ids_misc();
bool is_ssl_session_decrypted();
- void examine_ssl_metadata(snort::Packet*);
- void set_client_appid_data(AppId, char*);
- void set_service_appid_data(AppId, char*, char*);
- void set_referred_payload_app_id_data(AppId);
- void set_payload_appid_data(AppId, char*);
- void check_app_detection_restart();
+ void examine_ssl_metadata(snort::Packet*, AppidChangeBits& change_bits);
+ void set_client_appid_data(AppId, char*, AppidChangeBits& change_bits);
+ void set_service_appid_data(AppId, char*, char*, AppidChangeBits& change_bits);
+ void set_referred_payload_app_id_data(AppId, AppidChangeBits& change_bits);
+ void set_payload_appid_data(AppId, char*, AppidChangeBits& change_bits);
+ void check_app_detection_restart(AppidChangeBits& change_bits);
void update_encrypted_app_id(AppId);
- void examine_rtmp_metadata();
+ void examine_rtmp_metadata(AppidChangeBits& change_bits);
void sync_with_snort_protocol_id(AppId, snort::Packet*);
void stop_rna_service_inspection(snort::Packet*, AppidSessionDirection);
AppIdHttpSession* hsession = nullptr;
AppIdDnsSession* dsession = nullptr;
- void reinit_session_data();
+ void reinit_session_data(AppidChangeBits& change_bits);
void delete_session_data();
static THREAD_LOCAL uint32_t appid_flow_data_id;
char* AppIdSessionApi::get_tls_host()
{
if (asd->tsession)
- return asd->tsession->tls_host;
+ return asd->tsession->get_tls_host();
return nullptr;
}
snprintf(version, sizeof(version), "%d.%d.%d", major, minor, lesser);
add_app(args.asd, APP_ID_AOL_INSTANT_MESSENGER, APP_ID_AOL_INSTANT_MESSENGER,
- version);
+ version, args.change_bits);
}
}
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_BITTORRENT, APP_ID_BITTORRENT, nullptr);
+ add_app(args.asd, APP_ID_BITTORRENT, APP_ID_BITTORRENT, nullptr, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_BITTORRENT, APP_ID_BITTRACKER_CLIENT, nullptr);
+ add_app(args.asd, APP_ID_BITTORRENT, APP_ID_BITTRACKER_CLIENT, nullptr, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_MSN_MESSENGER, product_id, (char*)version);
+ add_app(args.asd, APP_ID_MSN_MESSENGER, product_id, (char*)version, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
}
- add_app(args.asd, APP_ID_RTP, APP_ID_RTP, nullptr);
+ add_app(args.asd, APP_ID_RTP, APP_ID_RTP, nullptr, args.change_bits);
return APPID_SUCCESS;
}
if (sm_ret != APPID_SUCCESS)
return sm_ret;
- add_app(args.asd, APP_ID_SSH, fd->client_id, (const char*)fd->version);
+ add_app(args.asd, APP_ID_SSH, fd->client_id, (const char*)fd->version, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_TIMBUKTU, APP_ID_TIMBUKTU, nullptr);
+ add_app(args.asd, APP_ID_TIMBUKTU, APP_ID_TIMBUKTU, nullptr, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_ORACLE_TNS, APP_ID_ORACLE_DATABASE, fd->version);
+ add_app(args.asd, APP_ID_ORACLE_TNS, APP_ID_ORACLE_DATABASE, fd->version, args.change_bits);
if (user_start && user_end && ((user_size = user_end - user_start) > 0))
{
/* we truncate extra long usernames */
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_VNC_RFB, APP_ID_VNC, (const char*)fd->version);
+ add_app(args.asd, APP_ID_VNC_RFB, APP_ID_VNC, (const char*)fd->version, args.change_bits);
return APPID_SUCCESS;
}
return APPID_INPROCESS;
done:
- add_app(args.asd, APP_ID_YAHOO, product_id, (char*)version);
+ add_app(args.asd, APP_ID_YAHOO, product_id, (char*)version, args.change_bits);
return APPID_SUCCESS;
}
return APPID_SESSION_SUCCESS;
}
-int ClientDiscovery::exec_client_detectors(AppIdSession& asd, Packet* p, AppidSessionDirection direction)
+int ClientDiscovery::exec_client_detectors(AppIdSession& asd, Packet* p,
+ AppidSessionDirection direction, AppidChangeBits& change_bits)
{
int ret = APPID_INPROCESS;
if (asd.client_detector != nullptr)
{
- AppIdDiscoveryArgs disco_args(p->data, p->dsize, direction, asd, p);
+ AppIdDiscoveryArgs disco_args(p->data, p->dsize, direction, asd, p, change_bits);
ret = asd.client_detector->validate(disco_args);
if (appidDebug->is_active())
LogMessage("AppIdDbg %s %s client detector returned %s (%d)\n",
{
for ( auto kv = asd.client_candidates.begin(); kv != asd.client_candidates.end(); )
{
- AppIdDiscoveryArgs disco_args(p->data, p->dsize, direction, asd, p);
+ AppIdDiscoveryArgs disco_args(p->data, p->dsize, direction, asd, p, change_bits);
int result = kv->second->validate(disco_args);
if (appidDebug->is_active())
LogMessage("AppIdDbg %s %s client candidate returned %s (%d)\n",
return ret;
}
-bool ClientDiscovery::do_client_discovery(AppIdSession& asd, Packet* p, AppidSessionDirection direction)
+bool ClientDiscovery::do_client_discovery(AppIdSession& asd, Packet* p,
+ AppidSessionDirection direction, AppidChangeBits& change_bits)
{
bool isTpAppidDiscoveryDone = false;
AppInfoTableEntry* entry;
{
/* get out if we've already tried to validate a client app */
if (!asd.is_client_detected() )
- ret = exec_client_detectors(asd, p, direction);
+ ret = exec_client_detectors(asd, p, direction, change_bits);
}
else if ( asd.service_disco_state != APPID_DISCO_STATE_STATEFUL
&& asd.get_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS) )
{
- ret = exec_client_detectors(asd, p, direction);
+ ret = exec_client_detectors(asd, p, direction, change_bits);
}
switch (ret)
{
/* get out if we've already tried to validate a client app */
if (!asd.is_client_detected())
- ret = exec_client_detectors(asd, p, direction);
+ ret = exec_client_detectors(asd, p, direction, change_bits);
}
else if ( asd.service_disco_state != APPID_DISCO_STATE_STATEFUL
&& asd.get_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS) )
- ret = exec_client_detectors(asd, p, direction);
+ ret = exec_client_detectors(asd, p, direction, change_bits);
if ( ret < 0 )
{
void finalize_client_plugins();
void release_thread_resources();
- bool do_client_discovery(AppIdSession&, snort::Packet*, AppidSessionDirection direction);
+ bool do_client_discovery(AppIdSession&, snort::Packet*,
+ AppidSessionDirection direction, AppidChangeBits& change_bits);
private:
ClientDiscovery(AppIdInspector& ins);
void initialize() override;
- int exec_client_detectors(AppIdSession&, snort::Packet*, AppidSessionDirection direction);
+ int exec_client_detectors(AppIdSession&, snort::Packet*,
+ AppidSessionDirection direction, AppidChangeBits& change_bits);
ClientAppMatch* find_detector_candidates(const snort::Packet* pkt, IpProtocol);
void create_detector_candidates_list(AppIdSession&, snort::Packet*);
int get_detector_candidates_list(AppIdSession&, snort::Packet*, AppidSessionDirection direction);
case APPID_SUCCESS:
success:
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
- return add_service(args.asd, args.pkt, args.dir, APP_ID_DNS);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DNS);
case APPID_INVALID_CLIENT:
invalid:
case APPID_INPROCESS:
inprocess:
- add_app(args.asd, APP_ID_NONE, APP_ID_DNS, nullptr);
+ add_app(args.asd, APP_ID_NONE, APP_ID_DNS, nullptr, args.change_bits);
service_inprocess(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
- return add_service(args.asd, args.pkt, args.dir, APP_ID_DNS);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DNS);
not_compatible:
incompatible_data(args.asd, args.pkt, args.dir);
return APPID_NOMATCH;
inprocess:
- add_app(args.asd, APP_ID_NONE, APP_ID_DNS, nullptr);
+ add_app(args.asd, APP_ID_NONE, APP_ID_DNS, nullptr, args.change_bits);
service_inprocess(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
}
int HttpClientDetector::validate(AppIdDiscoveryArgs& args)
{
- add_app(args.asd, APP_ID_HTTP, APP_ID_HTTP + GENERIC_APP_OFFSET, nullptr);
+ add_app(args.asd, APP_ID_HTTP, APP_ID_HTTP + GENERIC_APP_OFFSET, nullptr, args.change_bits);
args.asd.client_disco_state = APPID_DISCO_STATE_FINISHED;
- http_service_detector->add_service(args.asd, args.pkt, args.dir, APP_ID_HTTP);
+ http_service_detector->add_service(args.change_bits, args.asd, args.pkt,
+ args.dir, APP_ID_HTTP);
args.asd.service_disco_state = APPID_DISCO_STATE_FINISHED;
args.asd.set_session_flags(APPID_SESSION_CLIENT_DETECTED | APPID_SESSION_SERVICE_DETECTED);
args.asd.clear_session_flags(APPID_SESSION_CONTINUE);
fd->count++;
if (fd->count == MIN_CMDS)
{
- add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr);
+ add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr, args.change_bits);
fd->detected = 1;
if (fd->got_user)
{
fd->count++;
if (fd->count == MIN_CMDS)
{
- add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr);
+ add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr, args.change_bits);
fd->detected = 1;
if (fd->got_user)
{
fd->count++;
if (fd->count == MIN_CMDS)
{
- add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr);
+ add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr, args.change_bits);
fd->detected = 1;
if (fd->got_user)
{
fd->count++;
if (fd->count == MIN_CMDS)
{
- add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr);
+ add_app(args.asd, APP_ID_IMAP, APP_ID_IMAP, nullptr, args.change_bits);
fd->detected = 1;
if (fd->got_user)
{
{
if ((id->flags & IMAP_FLAG_RESULT_OK) &&
dd->client.state == IMAP_CLIENT_STATE_STARTTLS_CMD)
- return add_service(args.asd, args.pkt, args.dir, APP_ID_IMAPS);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_IMAPS);
if (id->count >= IMAP_COUNT_THRESHOLD && !args.asd.is_service_detected())
- return add_service(args.asd, args.pkt, args.dir, APP_ID_IMAP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_IMAP);
}
else if (!args.asd.is_service_detected())
{
static KerberosServiceDetector* krb_service_detector;
static int krb_walk_server_packet(KRBState* krbs, const uint8_t* s, const uint8_t* end,
- AppIdSession& asd, snort::Packet* pkt, const AppidSessionDirection dir, const char* reqCname)
+ AppIdSession& asd, snort::Packet* pkt, const AppidSessionDirection dir,
+ const char* reqCname, AppidChangeBits& change_bits)
{
static const uint8_t KRB_SERVER_VERSION[] = "\x0a0\x003\x002\x001";
static const uint8_t KRB_SERVER_TYPE[] = "\x0a1\x003\x002\x001";
/*end of server response message */
if (krbs->flags & KRB_FLAG_SERVICE_DETECTED)
if (!asd.is_service_detected() && pkt)
- krb_service_detector->add_service(asd, pkt, dir, APP_ID_KERBEROS,
+ krb_service_detector->add_service(change_bits, asd, pkt, dir, APP_ID_KERBEROS,
nullptr, krbs->ver, nullptr);
if (krbs->flags & KRB_FLAG_AUTH_FAILED)
return APPID_SUCCESS;
}
- if (krb_walk_server_packet(&fd->svr_state, s, end, args.asd, args.pkt, args.dir, fd->clnt_state.cname) ==
- KRB_FAILED)
+ if (krb_walk_server_packet(&fd->svr_state, s, end, args.asd, args.pkt, args.dir,
+ fd->clnt_state.cname, args.change_bits) == KRB_FAILED)
{
if (!args.asd.is_service_detected())
{
int KerberosClientDetector::krb_walk_client_packet(KRBState* krbs, const uint8_t* s,
- const uint8_t* end, AppIdSession& asd)
+ const uint8_t* end, AppIdSession& asd, AppidChangeBits& change_bits)
{
static const uint8_t KRB_CLIENT_VERSION[] = "\x0a1\x003\x002\x001";
static const uint8_t KRB_CLIENT_TYPE[] = "\x0a2\x003\x002\x001";
{
if (!krbs->added)
{
- add_app(asd, APP_ID_KERBEROS, APP_ID_KERBEROS, krbs->ver);
+ add_app(asd, APP_ID_KERBEROS, APP_ID_KERBEROS, krbs->ver, change_bits);
krbs->added = 1;
}
krbs->state = KRB_STATE_APP;
if (args.dir == APP_ID_FROM_INITIATOR)
{
- if (krb_walk_client_packet(&fd->clnt_state, s, end, args.asd) == KRB_FAILED)
+ if (krb_walk_client_packet(&fd->clnt_state, s, end, args.asd, args.change_bits) == KRB_FAILED)
{
args.asd.set_client_detected();
args.asd.clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
}
}
else if (krb_walk_server_packet(&fd->svr_state, s, end, args.asd, nullptr, args.dir,
- fd->clnt_state.cname) == KRB_FAILED)
+ fd->clnt_state.cname, args.change_bits) == KRB_FAILED)
{
args.asd.clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
}
bool failed_login = false;
private:
- int krb_walk_client_packet(KRBState*, const uint8_t*, const uint8_t*, AppIdSession&);
+ int krb_walk_client_packet(KRBState*, const uint8_t*, const uint8_t*,
+ AppIdSession&, AppidChangeBits&);
};
class KerberosServiceDetector : public ServiceDetector
return APPID_NOMATCH;
}
- return add_service(args.asd, args.pkt, args.dir, id);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, id);
}
PatternClientDetector::PatternClientDetector(ClientDiscovery* cdm)
if (!id)
return APPID_EINVALID;
- add_app(args.asd, id, id, nullptr);
+ add_app(args.asd, id, id, nullptr, args.change_bits);
return APPID_SUCCESS;
}
}
static int pop3_server_validate(POP3DetectorData* dd, const uint8_t* data, uint16_t size,
- AppIdSession& asd, int server)
+ AppIdSession& asd, int server, AppidChangeBits& change_bits)
{
ServicePOP3Data* pd = &dd->server;
const uint8_t* begin = nullptr;
// we are potentially overriding the APP_ID_POP3 assessment that was made earlier.
asd.set_session_flags(APPID_SESSION_ENCRYPTED);
asd.clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
- pop3_client_detector->add_app(asd, APP_ID_POP3S, APP_ID_POP3S, nullptr);
+ pop3_client_detector->add_app(asd, APP_ID_POP3S, APP_ID_POP3S, nullptr, change_bits);
}
}
else if (dd->client.username) // possible only with non-TLS auth, therefore APP_ID_POP3
if (args.dir == APP_ID_FROM_RESPONDER)
{
- if (pop3_server_validate(dd, args.data, args.size, args.asd, 0))
+ if (pop3_server_validate(dd, args.data, args.size, args.asd, 0, args.change_bits))
args.asd.clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
return APPID_INPROCESS;
}
if (pattern_index >= PATTERN_POP3_OTHER)
{
// Still in non-secure mode and received a TRANSACTION-state command: POP3 found
- add_app(args.asd, APP_ID_POP3, APP_ID_POP3, nullptr);
+ add_app(args.asd, APP_ID_POP3, APP_ID_POP3, nullptr, args.change_bits);
fd->detected = 1;
}
else
return APPID_SUCCESS;
}
- if (!pop3_server_validate(dd, args.data, args.size, args.asd, 1))
+ if (!pop3_server_validate(dd, args.data, args.size, args.asd, 1, args.change_bits))
{
if (pd->count >= POP3_COUNT_THRESHOLD
&& !args.asd.is_service_detected())
{
add_service_consume_subtype(args.asd, args.pkt, args.dir,
dd->client.state == POP3_CLIENT_STATE_STLS_CMD ? APP_ID_POP3S : APP_ID_POP3,
- pd->vendor, pd->version[0] ? pd->version : nullptr, pd->subtype);
+ pd->vendor, pd->version[0] ? pd->version : nullptr, pd->subtype, args.change_bits);
pd->subtype = nullptr;
return APPID_SUCCESS;
}
client->get_handler().get_inspector());
}
- client_handler(sip_event, *asd);
- service_handler(sip_event, *asd);
+ AppidChangeBits change_bits;
+ client_handler(sip_event, *asd, change_bits);
+ service_handler(sip_event, *asd, change_bits);
+ AppIdDiscovery::publish_appid_event(change_bits, flow);
}
-void SipEventHandler::client_handler(SipEvent& sip_event, AppIdSession& asd)
+void SipEventHandler::client_handler(SipEvent& sip_event, AppIdSession& asd,
+ AppidChangeBits& change_bits)
{
AppId ClientAppId = APP_ID_SIP;
char* clientVersion = nullptr;
success:
if( !asd.is_client_detected() )
- client->add_app(asd, APP_ID_SIP, ClientAppId, clientVersion);
+ client->add_app(asd, APP_ID_SIP, ClientAppId, clientVersion, change_bits);
if ( !fd->user_name.empty() )
client->add_user(asd, fd->user_name.c_str(), APP_ID_SIP, true);
}
-void SipEventHandler::service_handler(SipEvent& sip_event, AppIdSession& asd)
+void SipEventHandler::service_handler(SipEvent& sip_event, AppIdSession& asd,
+ AppidChangeBits& change_bits)
{
ServiceSIPData* ss = (ServiceSIPData*)service->data_get(asd);
if ( !ss )
if ( !asd.is_service_detected() )
{
asd.set_session_flags(APPID_SESSION_CONTINUE);
- service->add_service(asd, sip_event.get_packet(), direction, APP_ID_SIP,
+ service->add_service(change_bits, asd, sip_event.get_packet(), direction, APP_ID_SIP,
ss->vendor[0] ? ss->vendor : nullptr);
if (appidDebug->is_active())
LogMessage("AppIdDbg %s Sip service detected. Setting APPID_SESSION_CONTINUE flag\n",
private:
SipEventHandler() = default;
- void client_handler(SipEvent&, AppIdSession&);
- void service_handler(SipEvent&, AppIdSession&);
+ void client_handler(SipEvent&, AppIdSession&, AppidChangeBits&);
+ void service_handler(SipEvent&, AppIdSession&, AppidChangeBits&);
static SipUdpClientDetector* client;
static SipServiceDetector* service;
// FIXIT-M - refactor this to reduce the number of function parameters
int SmtpClientDetector::extract_version_and_add_client_app(AppId clientId, const int prefix_len,
const uint8_t* product, const uint8_t* product_end, ClientSMTPData* const client_data,
- AppIdSession& asd, AppId appId)
+ AppIdSession& asd, AppId appId, AppidChangeBits& change_bits)
{
uint8_t* v_end = client_data->version + MAX_VERSION_SIZE - 1;
for (v = client_data->version; v < v_end && p < product_end; v++,p++)
*v = *p;
*v = 0;
- add_app(asd, appId, clientId, (char*)client_data->version);
+ add_app(asd, appId, clientId, (char*)client_data->version, change_bits);
return 0;
}
* Returns 0 if a recognized product is found. Otherwise returns 1.
*/
int SmtpClientDetector::identify_client_version(ClientSMTPData* const fd, const uint8_t* product,
- const uint8_t* data_end, AppIdSession& asd, snort::Packet*)
+ const uint8_t* data_end, AppIdSession& asd, snort::Packet*, AppidChangeBits& change_bits)
{
const uint8_t* p;
AppId appId = APP_ID_SMTP;
if (p >= data_end || *p != ' ')
return 1;
return extract_version_and_add_client_app(APP_ID_OUTLOOK,
- 2, p, data_end, fd, asd, appId);
+ 2, p, data_end, fd, asd, appId, change_bits);
}
else if (*p == ' ')
{
if (data_end-p >= (int)sizeof(EXPRESS) && memcmp(p, EXPRESS, sizeof(EXPRESS)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_OUTLOOK_EXPRESS,
- sizeof(EXPRESS), p, data_end, fd, asd, appId);
+ sizeof(EXPRESS), p, data_end, fd, asd, appId, change_bits);
}
else if (data_end-p >= (int)sizeof(IMO) && memcmp(p, IMO, sizeof(IMO)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_OUTLOOK,
- sizeof(IMO), p, data_end, fd, asd, appId);
+ sizeof(IMO), p, data_end, fd, asd, appId, change_bits);
}
}
}
sizeof(APP_SMTP_EVOLUTION)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_EVOLUTION,
- sizeof(APP_SMTP_EVOLUTION), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_EVOLUTION), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_LOTUS_NOTES) && memcmp(product, APP_SMTP_LOTUS_NOTES,
sizeof(APP_SMTP_LOTUS_NOTES)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_LOTUS_NOTES,
- sizeof(APP_SMTP_LOTUS_NOTES), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_LOTUS_NOTES), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_APPLEMAIL) && memcmp(product, APP_SMTP_APPLEMAIL,
sizeof(APP_SMTP_APPLEMAIL)-1) == 0)
}
*v = 0;
- add_app(asd, appId, APP_ID_APPLE_EMAIL, (char*)fd->version);
+ add_app(asd, appId, APP_ID_APPLE_EMAIL, (char*)fd->version, change_bits);
return 0;
}
else if (len >= sizeof(APP_SMTP_EUDORA) && memcmp(product, APP_SMTP_EUDORA,
sizeof(APP_SMTP_EUDORA)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_EUDORA,
- sizeof(APP_SMTP_EUDORA), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_EUDORA), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_EUDORAPRO) && memcmp(product, APP_SMTP_EUDORAPRO,
sizeof(APP_SMTP_EUDORAPRO)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_EUDORA_PRO,
- sizeof(APP_SMTP_EUDORAPRO), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_EUDORAPRO), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_AOL) && memcmp(product, APP_SMTP_AOL,
sizeof(APP_SMTP_AOL)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_AOL_EMAIL,
- sizeof(APP_SMTP_AOL), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_AOL), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_MUTT) && memcmp(product, APP_SMTP_MUTT,
sizeof(APP_SMTP_MUTT)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_MUTT,
- sizeof(APP_SMTP_MUTT), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_MUTT), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_KMAIL) && memcmp(product, APP_SMTP_KMAIL,
sizeof(APP_SMTP_KMAIL)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_KMAIL,
- sizeof(APP_SMTP_KMAIL), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_KMAIL), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_THUNDERBIRD) && memcmp(product, APP_SMTP_THUNDERBIRD,
sizeof(APP_SMTP_THUNDERBIRD)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_THUNDERBIRD,
- sizeof(APP_SMTP_THUNDERBIRD), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_THUNDERBIRD), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_MTHUNDERBIRD) && memcmp(product, APP_SMTP_MTHUNDERBIRD,
sizeof(APP_SMTP_MTHUNDERBIRD)-1) == 0)
{
return extract_version_and_add_client_app(APP_ID_THUNDERBIRD,
- sizeof(APP_SMTP_MTHUNDERBIRD), product, data_end, fd, asd, appId);
+ sizeof(APP_SMTP_MTHUNDERBIRD), product, data_end, fd, asd, appId, change_bits);
}
else if (len >= sizeof(APP_SMTP_MOZILLA) && memcmp(product, APP_SMTP_MOZILLA,
sizeof(APP_SMTP_MOZILLA)-1) == 0)
{
return extract_version_and_add_client_app(
APP_ID_THUNDERBIRD, sizeof(APP_SMTP_THUNDERBIRD_SHORT),
- p, data_end, fd, asd, appId);
+ p, data_end, fd, asd, appId, change_bits);
}
}
}
/* Because we can't see any further info without decryption we settle for
plain APP_ID_SMTPS instead of perhaps finding data that would make calling
ExtractVersion() worthwhile, So set the appid and call it good. */
- add_app(args.asd, APP_ID_SMTPS, APP_ID_SMTPS, nullptr);
+ add_app(args.asd, APP_ID_SMTPS, APP_ID_SMTPS, nullptr, args.change_bits);
goto done;
}
}
(len >= 1 && args.data[1] == '\n') ||
(len >= 2 && args.data[1] == '\r' && args.data[2] == '\n'))
{
- add_app(args.asd, APP_ID_SMTP, APP_ID_SMTP, nullptr);
+ add_app(args.asd, APP_ID_SMTP, APP_ID_SMTP, nullptr, args.change_bits);
goto done;
}
}
{
if (fd->headerline && fd->pos)
{
- identify_client_version(fd, fd->headerline, fd->headerline + fd->pos, args.asd, args.pkt);
+ identify_client_version(fd, fd->headerline, fd->headerline + fd->pos, args.asd, args.pkt, args.change_bits);
snort_free(fd->headerline);
fd->headerline = nullptr;
fd->pos = 0;
dd->client.decryption_countdown = 1
#endif
- add_service(args.asd, args.pkt, args.dir, APP_ID_SMTPS);
+ add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_SMTPS);
if(dd->need_continue > 0)
args.asd.set_session_flags(APPID_SESSION_ENCRYPTED | APPID_SESSION_STICKY_SERVICE | APPID_SESSION_CONTINUE);
if (dd->need_continue > 0)
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
- return add_service(args.asd, args.pkt, args.dir,
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir,
(fd->state == SMTP_SERVICE_STATE_STARTTLS) ? APP_ID_SMTPS : APP_ID_SMTP);
fail:
private:
int extract_version_and_add_client_app(AppId, const int prefix_len,
const uint8_t* product, const uint8_t* product_end, ClientSMTPData* const,
- AppIdSession&, AppId);
+ AppIdSession&, AppId, AppidChangeBits&);
int identify_client_version(ClientSMTPData* const, const uint8_t* product,
- const uint8_t* data_end, AppIdSession&, snort::Packet*);
+ const uint8_t* data_end, AppIdSession&, snort::Packet*, AppidChangeBits&);
};
class SmtpServiceDetector : public ServiceDetector
/*Phase2 - discuss AppIdServiceSubtype will be maintained on lua side therefore the last
parameter on the following call is nullptr. Subtype is not displayed on DC at present. */
- unsigned int retValue = ud->sd->add_service(*lsd->ldp.asd, lsd->ldp.pkt, lsd->ldp.dir,
- AppInfoManager::get_instance().get_appid_by_service_id(service_id),
+ unsigned int retValue = ud->sd->add_service(*lsd->ldp.change_bits, *lsd->ldp.asd, lsd->ldp.pkt,
+ lsd->ldp.dir, AppInfoManager::get_instance().get_appid_by_service_id(service_id),
vendor, version, nullptr);
lua_pushnumber(L, retValue);
return 1;
}
- ud->cd->add_app(*lsd->ldp.asd, service_id, client_id, version);
+ ud->cd->add_app(*lsd->ldp.asd, service_id, client_id, version, *lsd->ldp.change_bits);
lua_pushnumber(L, 0);
return 1;
}
const char* version = lua_tostring(L, 5);
ud->cd->add_app(*lsd->ldp.asd,
AppInfoManager::get_instance().get_appid_by_service_id(service_id),
- AppInfoManager::get_instance().get_appid_by_client_id(productId), version);
+ AppInfoManager::get_instance().get_appid_by_client_id(productId), version,
+ *lsd->ldp.change_bits);
lua_pushnumber(L, 0);
return 1;
LuaStateDescriptor* lsd = ud->validate_lua_state(true);
const char* info = lua_tostring(L, 2);
- ud->cd->add_info(*lsd->ldp.asd, info);
+ ud->cd->add_info(*lsd->ldp.asd, info, *lsd->ldp.change_bits);
lua_pushnumber(L, 0);
return 1;
}
unsigned int service_id = lua_tonumber(L, 2);
unsigned int client_id = lua_tonumber(L, 3);
- ud->cd->add_app(*lsd->ldp.asd, service_id, client_id, "");
+ ud->cd->add_app(*lsd->ldp.asd, service_id, client_id, "", *lsd->ldp.change_bits);
lua_pushnumber(L, 0);
return 1;
}
/*Phase2 - discuss AppIdServiceSubtype will be maintained on lua side therefore the last
parameter on the following call is nullptr.
Subtype is not displayed on DC at present. */
- unsigned retValue = ud->sd->add_service(*lsd->ldp.asd, lsd->ldp.pkt,
+ unsigned retValue = ud->sd->add_service(*lsd->ldp.change_bits, *lsd->ldp.asd, lsd->ldp.pkt,
lsd->ldp.dir, service_id);
lua_pushnumber(L, retValue);
ldp.size = args.size;
ldp.dir = args.dir;
ldp.asd = &args.asd;
+ ldp.change_bits = &args.change_bits;
ldp.pkt = args.pkt;
const char* validateFn = package_info.validateFunctionName.c_str();
size = args.size;
dir = args.dir;
asd = &args.asd;
+ change_bits = &args.change_bits;
pkt = args.pkt;
}
uint16_t size = 0;
AppidSessionDirection dir = APP_ID_FROM_INITIATOR;
AppIdSession* asd;
+ AppidChangeBits* change_bits = nullptr;
snort::Packet* pkt = nullptr;
uint8_t macAddress[6] = { 0 };
};
goto inprocess;
}
- return add_service(args.asd, args.pkt, args.dir, APP_ID_BATTLEFIELD);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_BATTLEFIELD);
fail:
fail_service(args.asd, args.pkt, args.dir);
return APPID_NOMATCH;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_BGP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_BGP);
}
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_BITTORRENT);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_BITTORRENT);
fail:
fail_service(args.asd, args.pkt, args.dir);
if (!args.asd.is_service_detected())
{
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
- add_service(args.asd, args.pkt, args.dir, APP_ID_DHCP);
+ add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DHCP);
}
return APPID_SUCCESS;
size -= length;
}
if (retval == APPID_SUCCESS)
- return add_service(args.asd, args.pkt, args.dir, APP_ID_DCE_RPC);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DCE_RPC);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
size -= length;
}
if (retval == APPID_SUCCESS)
- return add_service(args.asd, args.pkt, args.dir, APP_ID_DCE_RPC);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_DCE_RPC);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
}
int ServiceDetector::update_service_data(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir, AppId appId,
- const char* vendor, const char* version)
+ const char* vendor, const char* version, AppidChangeBits& change_bits)
{
uint16_t port = 0;
const SfIp* ip = nullptr;
asd.service_detector = this;
asd.service.set_vendor(vendor);
- asd.service.set_version(version);
+ asd.service.set_version(version, change_bits);
asd.set_service_detected();
asd.service.set_id(appId);
int ServiceDetector::add_service_consume_subtype(AppIdSession& asd, const Packet* pkt,
AppidSessionDirection dir, AppId appId, const char* vendor, const char* version,
- AppIdServiceSubtype* subtype)
+ AppIdServiceSubtype* subtype, AppidChangeBits& change_bits)
{
asd.subtype = subtype;
- return update_service_data(asd, pkt, dir, appId, vendor, version);
+ return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits);
}
-int ServiceDetector::add_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir,
- AppId appId, const char* vendor, const char* version, const AppIdServiceSubtype* 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)
{
AppIdServiceSubtype* new_subtype = nullptr;
new_subtype = tmp_subtype;
}
asd.subtype = new_subtype;
- return update_service_data(asd, pkt, dir, appId, vendor, version);
+ return update_service_data(asd, pkt, dir, appId, vendor, version, change_bits);
}
int ServiceDetector::incompatible_data(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir)
void release_thread_resources() override { }
void register_appid(AppId, unsigned extractsInfo) override;
int service_inprocess(AppIdSession&, const snort::Packet*, AppidSessionDirection dir);
- int add_service(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId, const char* vendor = nullptr,
- const char* version = nullptr, const snort::AppIdServiceSubtype* = nullptr);
- int add_service_consume_subtype(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId,
- const char* vendor, const char* version, snort::AppIdServiceSubtype*);
+ int add_service(AppidChangeBits&, AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId,
+ const char* vendor = nullptr, const char* version = nullptr,
+ const snort::AppIdServiceSubtype* = nullptr);
+ int add_service_consume_subtype(AppIdSession&, const snort::Packet*,
+ AppidSessionDirection dir, AppId, const char* vendor, const char* version,
+ snort::AppIdServiceSubtype*, AppidChangeBits&);
int incompatible_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir);
int fail_service(AppIdSession&, const snort::Packet*, AppidSessionDirection dir);
void initialize_expected_session(AppIdSession&, AppIdSession&, uint64_t flags, AppidSessionDirection dir);
private:
- int update_service_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId, const char* vendor,
- const char* version);
+ int update_service_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId,
+ const char* vendor, const char* version, AppidChangeBits& change_bits);
};
#endif
}
if (args.asd.protocol == IpProtocol::TCP)
- return tcp_validate(data, size, args.dir, args.asd, args.pkt, fd);
+ return tcp_validate(data, size, args.dir, args.asd, args.pkt, fd, args.change_bits);
else
- return udp_validate(data, size, args.dir, args.asd, args.pkt, fd);
+ return udp_validate(data, size, args.dir, args.asd, args.pkt, fd, args.change_bits);
}
int DirectConnectServiceDetector::tcp_validate(const uint8_t* data, uint16_t size, const AppidSessionDirection dir,
- AppIdSession& asd, const Packet* pkt, ServiceData* serviceData)
+ AppIdSession& asd, const Packet* pkt, ServiceData* serviceData, AppidChangeBits& change_bits)
{
switch (serviceData->state)
{
goto inprocess;
}
- return add_service(asd, pkt, dir, APP_ID_DIRECT_CONNECT);
+ return add_service(change_bits, asd, pkt, dir, APP_ID_DIRECT_CONNECT);
fail:
fail_service(asd, pkt, dir);
}
int DirectConnectServiceDetector::udp_validate(const uint8_t* data, uint16_t size, const AppidSessionDirection dir,
- AppIdSession& asd, const Packet* pkt, ServiceData* serviceData)
+ AppIdSession& asd, const Packet* pkt, ServiceData* serviceData, AppidChangeBits& change_bits)
{
if (dir == APP_ID_FROM_RESPONDER && serviceData->state == CONN_STATE_SERVICE_DETECTED)
{
}
reportSuccess:
- return add_service(asd, pkt, dir, APP_ID_DIRECT_CONNECT);
+ return add_service(change_bits, asd, pkt, dir, APP_ID_DIRECT_CONNECT);
fail:
fail_service(asd, pkt, dir);
private:
int tcp_validate(const uint8_t* data, uint16_t size, const AppidSessionDirection dir, AppIdSession&,
- const snort::Packet*, ServiceData*);
+ const snort::Packet*, ServiceData*, AppidChangeBits&);
int udp_validate(const uint8_t* data, uint16_t size, const AppidSessionDirection dir, AppIdSession&,
- const snort::Packet*, ServiceData*);
+ const snort::Packet*, ServiceData*, AppidChangeBits&);
};
#endif
}
}
-int ServiceDiscovery::identify_service(AppIdSession& asd, Packet* p, AppidSessionDirection dir)
+int ServiceDiscovery::identify_service(AppIdSession& asd, Packet* p,
+ AppidSessionDirection dir, AppidChangeBits& change_bits)
{
ServiceDiscoveryState* sds = nullptr;
bool got_brute_force = false;
int ret = APPID_NOMATCH;
bool got_incompatible_service = false;
bool got_fail_service = false;
- AppIdDiscoveryArgs args(p->data, p->dsize, dir, asd, p);
+ AppIdDiscoveryArgs args(p->data, p->dsize, dir, asd, p, change_bits);
/* If we already have a service to try, then try it out. */
if ( asd.service_detector )
{
return asd.add_flow_data_id(21, ftp_service);
}
-bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p, AppidSessionDirection direction)
+bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p,
+ AppidSessionDirection direction, AppidChangeBits& change_bits)
{
bool isTpAppidDiscoveryDone = false;
if (asd.service_disco_state == APPID_DISCO_STATE_STATEFUL)
{
- identify_service(asd, p, direction);
+ identify_service(asd, p, direction, change_bits);
isTpAppidDiscoveryDone = true;
//to stop executing validator after service has been detected by RNA.
if (asd.get_session_flags(APPID_SESSION_SERVICE_DETECTED |
AppId payload_id = APP_ID_NONE;
dns_host_scan_hostname((const uint8_t*)(dsession->get_host()), dsession->get_host_len(),
&client_id, &payload_id);
- asd.set_client_appid_data(client_id, nullptr);
+ asd.set_client_appid_data(client_id, nullptr, change_bits);
}
else if (asd.service.get_id() == APP_ID_RTMP)
- asd.examine_rtmp_metadata();
+ asd.examine_rtmp_metadata(change_bits);
else if (asd.get_session_flags(APPID_SESSION_SSL_SESSION) && asd.tsession)
- asd.examine_ssl_metadata(p);
+ asd.examine_ssl_metadata(p, change_bits);
if (tp_app_id <= APP_ID_NONE && asd.get_session_flags(
APPID_SESSION_SERVICE_DETECTED | APPID_SESSION_NOT_A_SERVICE |
ServiceDetector* get_next_tcp_detector(AppIdDetectorsIterator&);
ServiceDetector* get_next_udp_detector(AppIdDetectorsIterator&);
- bool do_service_discovery(AppIdSession&, snort::Packet*, AppidSessionDirection dir);
- int identify_service(AppIdSession&, snort::Packet*, AppidSessionDirection dir);
+ bool do_service_discovery(AppIdSession&, snort::Packet*, AppidSessionDirection dir,
+ AppidChangeBits& change_bits);
+ int identify_service(AppIdSession&, snort::Packet*, AppidSessionDirection, AppidChangeBits&);
int fail_service(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, ServiceDetector*, ServiceDiscoveryState* sds = nullptr);
int incompatible_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, ServiceDetector*);
static int add_ftp_service_state(AppIdSession&);
return APPID_NOMATCH;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_AOL_INSTANT_MESSENGER);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir,
+ APP_ID_AOL_INSTANT_MESSENGER);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
| APPID_SESSION_DECRYPTED);
// FTPS only when encrypted==1 decrypted==0
- add_service(args.asd, args.pkt, args.dir, flags == APPID_SESSION_ENCRYPTED ?
- APP_ID_FTPS : APP_ID_FTP_CONTROL,
+ add_service(args.change_bits, args.asd, args.pkt, args.dir,
+ flags == APPID_SESSION_ENCRYPTED ? APP_ID_FTPS : APP_ID_FTP_CONTROL,
fd->vendor[0] ? fd->vendor : nullptr,
fd->version[0] ? fd->version : nullptr, nullptr);
}
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_IRCD);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_IRCD);
fail:
if (args.dir == APP_ID_FROM_RESPONDER)
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_PRINTSRV);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_PRINTSRV);
fail:
fail_service(args.asd, args.pkt, args.dir);
goto fail;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_MDNS);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_MDNS);
fail:
fail_service(args.asd, args.pkt, args.dir);
data += 6;
if (data >= end)
goto fail;
- return add_service(args.asd, args.pkt, args.dir, APP_ID_MYSQL, nullptr, (const char*)p, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_MYSQL,
+ nullptr, (const char*)p, nullptr);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
}
success:
- return add_service(args.asd, args.pkt, dir, APP_ID_NETBIOS_NS);
+ return add_service(args.change_bits, args.asd, args.pkt, dir, APP_ID_NETBIOS_NS);
inprocess:
service_inprocess(args.asd, args.pkt, dir);
goto inprocess;
if ( !args.asd.is_service_detected() )
- if ( add_service(args.asd, args.pkt, dir, nd->serviceAppId) == APPID_SUCCESS )
+ if ( add_service(args.change_bits, args.asd, args.pkt, dir, nd->serviceAppId) == APPID_SUCCESS )
add_miscellaneous_info(args.asd, nd->miscAppId);
return APPID_SUCCESS;
{
if ( dir == APP_ID_FROM_RESPONDER )
{
- if ( add_service(args.asd, args.pkt, dir, serviceAppId) == APPID_SUCCESS )
+ if ( add_service(args.change_bits, args.asd, args.pkt, dir, serviceAppId) == APPID_SUCCESS )
add_miscellaneous_info(args.asd, miscAppId);
}
}
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_NNTP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_NNTP);
fail:
fail_service(args.asd, args.pkt, args.dir);
goto fail;
}
- return add_service(args.asd, args.pkt, args.dir, APP_ID_NTP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_NTP);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_RADIUS);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_RADIUS);
not_compatible:
incompatible_data(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_RADIUS_ACCT);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_RADIUS_ACCT);
not_compatible:
incompatible_data(args.asd, args.pkt, args.dir);
p++;
}
*v = 0;
- return add_service(args.asd, args.pkt, args.dir, APP_ID_REGTEST, nullptr, version, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_REGTEST, nullptr,
+ version, nullptr);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
p++;
}
*v = 0;
- return add_service(args.asd, args.pkt, args.dir, APP_ID_REGTEST1, nullptr, version, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_REGTEST1, nullptr,
+ version, nullptr);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
p++;
}
*v = 0;
- return add_service(args.asd, args.pkt, args.dir, APP_ID_REGTEST2, nullptr, version, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_REGTEST2, nullptr,
+ version, nullptr);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
success:
if (!args.asd.is_service_detected())
- return add_service(args.asd, args.pkt, args.dir, APP_ID_EXEC);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_EXEC);
bail:
if (!args.asd.is_service_detected())
p++;
}
*v = 0;
- return add_service(args.asd, args.pkt, args.dir, APP_ID_VNC_RFB, nullptr, version, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_VNC_RFB,
+ nullptr, version, nullptr);
inprocess:
service_inprocess(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_RLOGIN);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_RLOGIN);
fail:
fail_service(args.asd, args.pkt, args.dir);
else
subtype = nullptr;
- add_service(args.asd, pkt, dir, APP_ID_SUN_RPC, nullptr, nullptr, subtype);
+ add_service(args.change_bits, args.asd, pkt, dir, APP_ID_SUN_RPC,
+ nullptr, nullptr, subtype);
}
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
return APPID_SUCCESS;
}
else
subtype = nullptr;
- add_service(args.asd, pkt, dir, APP_ID_SUN_RPC, nullptr, nullptr, subtype);
+ add_service(args.change_bits, args.asd, pkt, dir, APP_ID_SUN_RPC,
+ nullptr, nullptr, subtype);
}
args.asd.set_session_flags(APPID_SESSION_CONTINUE);
return APPID_SUCCESS;
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_SHELL);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_SHELL);
bail:
incompatible_data(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_RSYNC);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_RSYNC);
fail:
fail_service(args.asd, args.pkt, args.dir);
{
if ( !hsession->get_field(MISC_URL_FID) )
{
- hsession->set_field(MISC_URL_FID, new std::string(ss->swfUrl));
+ hsession->set_field(MISC_URL_FID, new std::string(ss->swfUrl), args.change_bits);
args.asd.scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
{
if ( !hsession->get_field(REQ_REFERER_FID) &&
!args.asd.config->mod_config->referred_appId_disabled )
- hsession->set_field(REQ_REFERER_FID, new std::string(ss->pageUrl));
+ hsession->set_field(REQ_REFERER_FID, new std::string(ss->pageUrl), args.change_bits);
snort_free(ss->pageUrl);
ss->pageUrl = nullptr;
}
- return add_service(args.asd, args.pkt, args.dir, APP_ID_RTMP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_RTMP);
}
version_str = nullptr;
break;
}
- return add_service(args.asd, args.pkt, args.dir, APP_ID_SNMP, SNMP_VENDOR_STR, version_str, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_SNMP,
+ SNMP_VENDOR_STR, version_str, nullptr);
bail:
incompatible_data(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
case APPID_SUCCESS:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_SSH, ss->vendor, ss->version, nullptr);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_SSH,
+ ss->vendor, ss->version, nullptr);
case APPID_NOMATCH:
fail:
/* TLS Host */
if (ss->host_name)
{
- if (args.asd.tsession->tls_host)
- snort_free(args.asd.tsession->tls_host);
- args.asd.tsession->tls_host = ss->host_name;
- args.asd.tsession->tls_host_strlen = ss->host_name_strlen;
+ args.asd.tsession->set_tls_host(ss->host_name, 0, args.change_bits);
args.asd.scan_flags |= SCAN_SSL_HOST_FLAG;
}
else if (ss->common_name)
{
// use common name (from server) if we didn't see host name (from client)
- char* common_name = snort_strdup(ss->common_name);
-
- if (args.asd.tsession->tls_host)
- snort_free(args.asd.tsession->tls_host);
- args.asd.tsession->tls_host = common_name;
- args.asd.tsession->tls_host_strlen = ss->common_name_strlen;
+ args.asd.tsession->set_tls_host(ss->common_name, ss->common_name_strlen,
+ args.change_bits);
args.asd.scan_flags |= SCAN_SSL_HOST_FLAG;
}
/* TLS Common Name */
if (ss->common_name)
- {
- if (args.asd.tsession->tls_cname)
- snort_free(args.asd.tsession->tls_cname);
- args.asd.tsession->tls_cname = ss->common_name;
- args.asd.tsession->tls_cname_strlen = ss->common_name_strlen;
- }
+ args.asd.tsession->set_tls_cname(ss->common_name, 0);
/* TLS Org Unit */
if (ss->org_name)
- {
- if (args.asd.tsession->tls_orgUnit)
- snort_free(args.asd.tsession->tls_orgUnit);
- args.asd.tsession->tls_orgUnit = ss->org_name;
- args.asd.tsession->tls_orgUnit_strlen = ss->org_name_strlen;
- }
+ args.asd.tsession->set_tls_org_unit(ss->org_name, 0);
ss->host_name = ss->common_name = ss->org_name = nullptr;
}
- return add_service(args.asd, args.pkt, args.dir, getSslServiceAppId(args.pkt->ptrs.sp));
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir,
+ getSslServiceAppId(args.pkt->ptrs.sp));
}
AppId getSslServiceAppId(short srcPort)
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_TELNET);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_TELNET);
fail:
fail_service(args.asd, args.pkt, args.dir);
success:
if (appidDebug->is_active())
LogMessage("AppIdDbg %s TFTP success\n", appidDebug->get_debug_session());
- return add_service(args.asd, args.pkt, args.dir, APP_ID_TFTP);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_TFTP);
bail:
incompatible_data(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_TIMBUKTU);
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_TIMBUKTU);
fail:
fail_service(args.asd, args.pkt, args.dir);
return APPID_INPROCESS;
success:
- return add_service(args.asd, args.pkt, args.dir, APP_ID_ORACLE_TNS,
+ return add_service(args.change_bits, args.asd, args.pkt, args.dir, APP_ID_ORACLE_TNS,
nullptr, ss->version ? ss->version : nullptr, nullptr);
fail:
SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
)
+add_cpputest( appid_discovery_test
+ SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
+)
+
add_cpputest( appid_expected_flags_test
SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
)
mock_flow_data= nullptr;
SfIp ip;
ip.pton(AF_INET, "192.168.1.222");
- val = appid_api.consume_ha_state(flow, (uint8_t*)&appHA, 0, IpProtocol::TCP, &ip, 1066);
+ appid_api.consume_ha_state(flow, (uint8_t*)&appHA, 0, IpProtocol::TCP, &ip, 1066);
AppIdSession* session = (AppIdSession*)flow->get_flow_data(AppIdSession::inspector_id);
CHECK_TRUE(session);
CHECK_TRUE(session->get_tp_app_id() == appHA.appId[0]);
// test logic when service app is ftp control
appHA.appId[1] = APP_ID_FTP_CONTROL;
mock_flow_data= nullptr;
- val = appid_api.consume_ha_state(flow, (uint8_t*)&appHA, 0, IpProtocol::TCP, &ip, 1066);
+ appid_api.consume_ha_state(flow, (uint8_t*)&appHA, 0, IpProtocol::TCP, &ip, 1066);
session = (AppIdSession*)flow->get_flow_data(AppIdSession::inspector_id);
CHECK_TRUE(session);
uint64_t flags = session->get_session_flags(APPID_SESSION_CLIENT_DETECTED |
Flow* flow = nullptr;
AppIdSession* mock_session = nullptr;
+void AppIdHttpSession::set_http_change_bits(AppidChangeBits&, HttpFieldIds) {}
+
class TestDetector : public AppIdDetector
{
public:
TEST(appid_detector_tests, add_info)
{
const char* info_url = "https://tools.ietf.org/html/rfc793";
+ AppidChangeBits change_bits;
AppIdDetector* ad = new TestDetector;
MockAppIdHttpSession* hsession = (MockAppIdHttpSession*)mock_session->get_http_session();
- ad->add_info(*mock_session, info_url);
+ ad->add_info(*mock_session, info_url, change_bits);
STRCMP_EQUAL(hsession->get_cfield(MISC_URL_FID), URL);
hsession->reset();
- ad->add_info(*mock_session, info_url);
+ ad->add_info(*mock_session, info_url, change_bits);
STRCMP_EQUAL(mock_session->get_http_session()->get_cfield(MISC_URL_FID), info_url);
delete ad;
}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 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.
+//--------------------------------------------------------------------------
+// appid_discovery_test.cc author Masud Hasan <mashasan@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define APPID_MOCK_INSPECTOR_H // avoiding mocked inspector
+
+#include "network_inspectors/appid/appid_discovery.cc"
+
+#include "search_engines/search_tool.h"
+#include "utils/sflsq.cc"
+
+#include "appid_mock_session.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+namespace snort
+{
+// Stubs for packet
+Packet::Packet(bool) {}
+Packet::~Packet() {}
+
+// Stubs for inspector
+Inspector::Inspector()
+{
+ set_api(nullptr);
+}
+Inspector::~Inspector() = default;
+bool Inspector::likes(Packet*) { return true; }
+bool Inspector::get_buf(const char*, Packet*, InspectionBuffer&) { return true; }
+class StreamSplitter* Inspector::get_splitter(bool) { return nullptr; }
+
+// Stubs for module
+Module::Module(char const*, char const*) {}
+bool Module::set(const char*, Value&, SnortConfig*) { return true; }
+void Module::sum_stats(bool) {}
+void Module::show_interval_stats(std::vector<unsigned>&, FILE*) {}
+void Module::show_stats() {}
+void Module::reset_stats() {}
+PegCount Module::get_global_count(char const*) const { return 0; }
+
+// Stubs for logs
+void LogMessage(const char*,...) {}
+void ErrorMessage(const char*,...) {}
+void LogLabel(const char*, FILE*) {}
+
+// Stubs for utils
+char* snort_strdup(const char* str)
+{
+ assert(str);
+ size_t n = strlen(str) + 1;
+ char* p = (char*)snort_alloc(n);
+ memcpy(p, str, n);
+ return p;
+}
+char* snort_strndup(const char* src, size_t)
+{
+ return snort_strdup(src);
+}
+time_t packet_time() { return std::time(0); }
+
+// Stubs for search_tool
+SearchTool::SearchTool(const char*, bool) {}
+SearchTool::~SearchTool() {}
+void SearchTool::add(const char*, unsigned, int, bool) {}
+void SearchTool::add(const char*, unsigned, void*, bool) {}
+void SearchTool::add(const uint8_t*, unsigned, int, bool) {}
+void SearchTool::add(const uint8_t*, unsigned, void*, bool) {}
+
+// Stubs for ip
+namespace ip
+{
+void IpApi::set(const SfIp& sip, const SfIp& dip)
+{
+ type = IAT_DATA;
+ src.set(sip);
+ dst.set(dip);
+ iph = nullptr;
+}
+} // namespace ip
+
+} // namespace snort
+
+// Stubs for publish
+static bool databus_publish_called = false;
+static char test_log[256];
+void DataBus::publish(const char*, DataEvent& event, Flow*)
+{
+ databus_publish_called = true;
+ AppidEvent* appid_event = (AppidEvent*)&event;
+ snprintf(test_log, 256, "Published change_bits == %s",
+ appid_event->get_change_bitset().to_string().c_str());
+}
+
+// Stubs for matchers
+static HttpPatternMatchers* http_matchers;
+HttpPatternMatchers::~HttpPatternMatchers() {}
+void HttpPatternMatchers::get_http_offsets(snort::Packet*, AppIdHttpSession*) {}
+HttpPatternMatchers* HttpPatternMatchers::get_instance()
+{
+ return http_matchers;
+}
+
+// Stubs for AppIdModule
+AppIdModule::AppIdModule(): snort::Module("appid_mock", "appid_mock_help") {}
+AppIdModule::~AppIdModule() {}
+void AppIdModule::sum_stats(bool) {}
+void AppIdModule::show_dynamic_stats() {}
+bool AppIdModule::begin(char const*, int, snort::SnortConfig*) { return true; }
+bool AppIdModule::end(char const*, int, snort::SnortConfig*) { return true; }
+bool AppIdModule::set(char const*, snort::Value&, snort::SnortConfig*) { return true; }
+const snort::Command* AppIdModule::get_commands() const { return nullptr; }
+const PegInfo* AppIdModule::get_pegs() const { return nullptr; }
+PegCount* AppIdModule::get_counts() const { return nullptr; }
+snort::ProfileStats* AppIdModule::get_profile() const { return nullptr; }
+
+// Stubs for config
+AppIdModuleConfig::~AppIdModuleConfig() {}
+AppIdConfig::AppIdConfig(AppIdModuleConfig*) {}
+AppIdConfig::~AppIdConfig() {}
+static AppIdModuleConfig app_config;
+static AppIdConfig my_app_config(&app_config);
+AppId AppIdConfig::get_port_service_id(IpProtocol, uint16_t)
+{
+ return APP_ID_NONE;
+}
+
+// Stubs for AppIdInspector
+AppIdInspector::AppIdInspector(AppIdModule&) {}
+AppIdInspector::~AppIdInspector() = default;
+void AppIdInspector::eval(snort::Packet*) { }
+bool AppIdInspector::configure(snort::SnortConfig*) { return true; }
+void AppIdInspector::show(snort::SnortConfig*) { }
+void AppIdInspector::tinit() { }
+void AppIdInspector::tterm() { }
+AppIdConfig* AppIdInspector::get_appid_config()
+{
+ my_app_config.mod_config = &app_config;
+ return &my_app_config;
+}
+
+// Stubs for AppInfoManager
+AppInfoTableEntry* AppInfoManager::get_app_info_entry(AppId)
+{
+ return nullptr;
+}
+const char* AppInfoManager::get_app_name(int32_t)
+{
+ return nullptr;
+}
+
+// Stubs for AppIdSession
+void AppIdSession::sync_with_snort_protocol_id(AppId, Packet*) {}
+void AppIdSession::check_app_detection_restart(AppidChangeBits&) {}
+void AppIdSession::set_client_appid_data(AppId, char*, AppidChangeBits&) {}
+void AppIdSession::examine_rtmp_metadata(AppidChangeBits&) {}
+void AppIdSession::examine_ssl_metadata(Packet*, AppidChangeBits&) {}
+void AppIdSession::update_encrypted_app_id(AppId) {}
+AppIdSession* AppIdSession::allocate_session(const Packet*, IpProtocol,
+ AppidSessionDirection, AppIdInspector&)
+{
+ return nullptr;
+}
+
+// Stubs for ServiceDiscovery
+void ServiceDiscovery::initialize() {}
+void ServiceDiscovery::finalize_service_patterns() {}
+void ServiceDiscovery::match_by_pattern(AppIdSession&, const Packet*, IpProtocol) {}
+void ServiceDiscovery::get_port_based_services(IpProtocol, uint16_t, AppIdSession&) {}
+void ServiceDiscovery::get_next_service(const Packet*, const AppidSessionDirection, AppIdSession&) {}
+int ServiceDiscovery::identify_service(AppIdSession&, Packet*, AppidSessionDirection,
+ AppidChangeBits&) { return 0; }
+int ServiceDiscovery::add_ftp_service_state(AppIdSession&) { return 0; }
+bool ServiceDiscovery::do_service_discovery(AppIdSession&, Packet*, AppidSessionDirection,
+ AppidChangeBits&) { return 0; }
+int ServiceDiscovery::incompatible_data(AppIdSession&, const Packet*,AppidSessionDirection,
+ ServiceDetector*) { return 0; }
+int ServiceDiscovery::fail_service(AppIdSession&, const Packet*, AppidSessionDirection,
+ ServiceDetector*, ServiceDiscoveryState*) { return 0; }
+int ServiceDiscovery::add_service_port(AppIdDetector*,
+ const ServiceDetectorPort&) { return APPID_EINVALID; }
+ServiceDiscovery::ServiceDiscovery(AppIdInspector& ins)
+ : AppIdDiscovery(ins) {}
+void ServiceDiscovery::release_instance() {}
+void ServiceDiscovery::release_thread_resources() {}
+ServiceDiscovery& ServiceDiscovery::get_instance(AppIdInspector* ins)
+{
+ static ServiceDiscovery s_discovery_manager(*ins);
+ return s_discovery_manager;
+}
+
+// Stubs for ClientDiscovery
+ClientDiscovery::ClientDiscovery(AppIdInspector& ins)
+ : AppIdDiscovery(ins) {}
+ClientDiscovery::~ClientDiscovery() {}
+void ClientDiscovery::initialize() {}
+void ClientDiscovery::finalize_client_plugins() {}
+void ClientDiscovery::release_instance() {}
+void ClientDiscovery::release_thread_resources() {}
+ClientDiscovery& ClientDiscovery::get_instance(AppIdInspector* ins)
+{
+ static ClientDiscovery c_discovery_manager(*ins);
+ return c_discovery_manager;
+}
+bool ClientDiscovery::do_client_discovery(AppIdSession&, Packet*,
+ AppidSessionDirection, AppidChangeBits&)
+{
+ return false;
+}
+
+// Stubs for misc items
+HostPortVal* HostPortCache::find(const SfIp*, uint16_t, IpProtocol)
+{
+ return nullptr;
+}
+void AppIdServiceState::check_reset(AppIdSession&, const SfIp*, uint16_t) {}
+int dns_host_scan_hostname(const uint8_t*, size_t, AppId*, AppId*)
+{
+ return 0;
+}
+bool do_tp_discovery(AppIdSession&, IpProtocol,
+ Packet*, AppidSessionDirection&, AppidChangeBits&)
+{
+ return true;
+}
+TPLibHandler* TPLibHandler::self = nullptr;
+THREAD_LOCAL AppIdStats appid_stats;
+THREAD_LOCAL AppIdDebug* appidDebug = nullptr;
+void AppIdDebug::activate(const Flow*, const AppIdSession*, bool) { active = false; }
+AppId find_length_app_cache(const LengthKey&)
+{
+ return APP_ID_NONE;
+}
+void check_session_for_AF_indicator(Packet*, AppidSessionDirection, AppId) {}
+AppId check_session_for_AF_forecast(AppIdSession&, Packet*, AppidSessionDirection, AppId)
+{
+ return APP_ID_UNKNOWN;
+}
+
+TEST_GROUP(appid_discovery_tests)
+{
+ void setup() override
+ {
+ appidDebug = new AppIdDebug();
+ http_matchers = new HttpPatternMatchers;
+ AppIdPegCounts::init_pegs();
+ }
+
+ void teardown() override
+ {
+ delete appidDebug;
+ delete http_matchers;
+ AppIdPegCounts::cleanup_pegs();
+ AppIdPegCounts::cleanup_peg_info();
+ }
+};
+
+TEST(appid_discovery_tests, event_published_when_ignoring_flow)
+{
+ // Testing event from do_pre_discovery() path
+ databus_publish_called = false;
+ test_log[0] = '\0';
+ Packet p;
+ DAQ_PktHdr_t pkth;
+ p.pkth = &pkth;
+ SfIp ip;
+ p.ptrs.ip_api.set(ip, ip);
+ AppIdModule app_module;
+ AppIdInspector ins(app_module);
+ AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins);
+ Flow* flow = new Flow;
+ flow->set_flow_data(asd);
+ p.flow = flow;
+ asd->config = &my_app_config;
+ asd->common.initiator_port = 21;
+ asd->common.initiator_ip.set("1.2.3.4");
+ asd->set_session_flags(APPID_SESSION_IGNORE_FLOW);
+
+ AppIdDiscovery::do_application_discovery(&p, ins);
+
+ // Detect changes in service, client, payload, and misc appid
+ CHECK_EQUAL(databus_publish_called, true);
+ STRCMP_EQUAL(test_log, "Published change_bits == 0000000001111");
+ delete asd;
+ delete flow;
+}
+
+TEST(appid_discovery_tests, event_published_when_processing_flow)
+{
+ // Testing event from do_discovery() path
+ databus_publish_called = false;
+ test_log[0] = '\0';
+ Packet p;
+ DAQ_PktHdr_t pkth;
+ p.pkth = &pkth;
+ SfIp ip;
+ p.ptrs.ip_api.set(ip, ip);
+ AppIdModule app_module;
+ AppIdInspector ins(app_module);
+ AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins);
+ Flow* flow = new Flow;
+ flow->set_flow_data(asd);
+ p.flow = flow;
+ asd->config = &my_app_config;
+ asd->common.initiator_port = 21;
+ asd->common.initiator_ip.set("1.2.3.4");
+
+ AppIdDiscovery::do_application_discovery(&p, ins);
+
+ // Detect changes in service, client, payload, and misc appid
+ CHECK_EQUAL(databus_publish_called, true);
+ STRCMP_EQUAL(test_log, "Published change_bits == 0000000001111");
+ delete asd;
+ delete flow;
+}
+
+TEST(appid_discovery_tests, change_bits_for_client_version)
+{
+ // Testing set_version
+ AppidChangeBits change_bits;
+ AppIdModule app_module;
+ AppIdInspector ins(app_module);
+ AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins);
+ const char* version = "3.0";
+ asd->client.set_version(version, change_bits);
+
+ // Detect changes in client version
+ CHECK_EQUAL(change_bits.test(APPID_VERSION_BIT), true);
+ delete asd;
+}
+
+TEST(appid_discovery_tests, change_bits_for_tls_host)
+{
+ // Testing set_tls_host
+ AppidChangeBits change_bits;
+ const char* host = "www.cisco.com";
+ TlsSession tls;
+ tls.set_tls_host(host, 0, change_bits);
+
+ // Detect changes in tls_host
+ CHECK_EQUAL(change_bits.test(APPID_TLSHOST_BIT), true);
+}
+
+TEST(appid_discovery_tests, change_bits_for_non_http_appid)
+{
+ // Testing FTP appid
+ databus_publish_called = false;
+ Packet p;
+ DAQ_PktHdr_t pkth;
+ p.pkth = &pkth;
+ SfIp ip;
+ p.ptrs.ip_api.set(ip, ip);
+ AppIdModule app_module;
+ AppIdInspector ins(app_module);
+ AppIdSession* asd = new AppIdSession(IpProtocol::TCP, nullptr, 21, ins);
+ Flow* flow = new Flow;
+ flow->set_flow_data(asd);
+ p.flow = flow;
+ asd->config = &my_app_config;
+ asd->common.initiator_port = 21;
+ asd->common.initiator_ip.set("1.2.3.4");
+ asd->misc_app_id = APP_ID_NONE;
+ asd->payload.set_id(APP_ID_NONE);
+ asd->client.set_id(APP_ID_CURL);
+ asd->service.set_id(APP_ID_FTP);
+
+ AppIdDiscovery::do_application_discovery(&p, ins);
+
+ // Detect event for FTP service and CURL client
+ CHECK_EQUAL(databus_publish_called, true);
+ CHECK_EQUAL(asd->client.get_id(), APP_ID_CURL);
+ CHECK_EQUAL(asd->service.get_id(), APP_ID_FTP);
+
+ // Testing DNS appid
+ databus_publish_called = false;
+ asd->misc_app_id = APP_ID_NONE;
+ asd->payload.set_id(APP_ID_NONE);
+ asd->client.set_id(APP_ID_NONE);
+ asd->service.set_id(APP_ID_DNS);
+ AppIdDiscovery::do_application_discovery(&p, ins);
+
+ // Detect event for DNS service
+ CHECK_EQUAL(databus_publish_called, true);
+ CHECK_EQUAL(asd->service.get_id(), APP_ID_DNS);
+
+ delete asd;
+ delete flow;
+}
+
+TEST(appid_discovery_tests, change_bits_to_string)
+{
+ // Testing that all bits from AppidChangeBit enum get translated
+ AppidChangeBits change_bits;
+ std::string str;
+
+ // Detect empty
+ change_bits_to_string(change_bits, str);
+ STRCMP_EQUAL(str.c_str(), "");
+
+ // Detect all; failure of this test means some bits from enum are missed in translation
+ change_bits.set();
+ change_bits_to_string(change_bits, str);
+ STRCMP_EQUAL(str.c_str(), "service, client, payload, misc, referred, host,"
+ " tls-host, url, user-agent, response, referrer, xff, client-version");
+
+ // Detect enum vs translator mismatch actually working
+ std::bitset<APPID_MAX_BIT+1> change_bits_extra;
+ change_bits_extra.set();
+ str.clear();
+ change_bits_to_string(*((AppidChangeBits*) &change_bits_extra), str);
+ STRCMP_EQUAL(str.c_str(), "service, client, payload, misc, referred, host, tls-host, url,"
+ " user-agent, response, referrer, xff, client-version, change_bits_to_string error!");
+}
+
+int main(int argc, char** argv)
+{
+ int rc = CommandLineTestRunner::RunAllTests(argc, argv);
+ return rc;
+}
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
+void AppIdHttpSession::set_http_change_bits(AppidChangeBits&, HttpFieldIds) {}
+
class MockServiceDetector : public ServiceDetector
{
public:
};
FakeHttpMsgHeader* fake_msg_header = nullptr;
+void AppIdDiscovery::publish_appid_event(AppidChangeBits&, snort::Flow*) {}
+
+void AppIdHttpSession::set_http_change_bits(AppidChangeBits&, HttpFieldIds) {}
+
const uint8_t* HttpEvent::get_content_type(int32_t& length)
{
global_field.set(0, nullptr);
}
bool HttpPatternMatchers::get_appid_from_url(char*, const char*, char**,
- const char*, AppId*, AppId*, AppId*, AppId*, bool)
+ const char*, AppId*, AppId*, AppId*, AppId* referredPayloadAppId, bool)
{
+ *referredPayloadAppId = APP_ID_FACEBOOK;
return true;
}
{
}
-void AppIdSession::set_client_appid_data(AppId, char*)
+void AppIdSession::set_client_appid_data(AppId, char*, AppidChangeBits&)
{
}
-void AppIdSession::set_service_appid_data(AppId, char*, char*)
+void AppIdSession::set_service_appid_data(AppId, char*, char*, AppidChangeBits&)
{
}
-void AppIdSession::set_payload_appid_data(AppId, char*)
+void AppIdSession::set_payload_appid_data(AppId, char*, AppidChangeBits&)
{
}
return true;
}
-void AppIdSession::set_referred_payload_app_id_data(AppId)
+void AppIdSession::set_referred_payload_app_id_data(AppId id, AppidChangeBits& change_bits)
{
+ if (id <= APP_ID_NONE)
+ return;
+
+ if (referred_payload_app_id != id)
+ {
+ referred_payload_app_id = id;
+ change_bits.set(APPID_REFERRED_BIT);
+ }
}
// AppIdDebug mock functions
// Set the fields using integers, then get them by HttpFieldIds,
// to make sure the order of the HttpFieldIds has not changed
// in appid_http_session.h.
- hsession.set_field( (HttpFieldIds)0, new std::string("agent") );
- hsession.set_field( (HttpFieldIds)1, new std::string("host") );
- hsession.set_field( (HttpFieldIds)2, new std::string("referer") );
- hsession.set_field( (HttpFieldIds)3, new std::string("uri") );
- hsession.set_field( (HttpFieldIds)4, new std::string("cookie") );
- hsession.set_field( (HttpFieldIds)5, new std::string("req_body") );
- hsession.set_field( (HttpFieldIds)6, new std::string("content_type") );
- hsession.set_field( (HttpFieldIds)7, new std::string("location") );
- hsession.set_field( (HttpFieldIds)8, new std::string("rsp_body") );
- hsession.set_field( (HttpFieldIds)9, new std::string("via") );
- hsession.set_field( (HttpFieldIds)10, new std::string("response_code") );
- hsession.set_field( (HttpFieldIds)11, new std::string("server") );
- hsession.set_field( (HttpFieldIds)12, new std::string("xww") );
- hsession.set_field( (HttpFieldIds)13, new std::string("url") );
+ AppidChangeBits change_bits;
+
+ hsession.set_field( (HttpFieldIds)0, new std::string("agent"), change_bits );
+ hsession.set_field( (HttpFieldIds)1, new std::string("host"), change_bits );
+ hsession.set_field( (HttpFieldIds)2, new std::string("referer"), change_bits );
+ hsession.set_field( (HttpFieldIds)3, new std::string("uri"), change_bits );
+ hsession.set_field( (HttpFieldIds)4, new std::string("cookie"), change_bits );
+ hsession.set_field( (HttpFieldIds)5, new std::string("req_body"), change_bits );
+ hsession.set_field( (HttpFieldIds)6, new std::string("content_type"), change_bits );
+ hsession.set_field( (HttpFieldIds)7, new std::string("location"), change_bits );
+ hsession.set_field( (HttpFieldIds)8, new std::string("rsp_body"), change_bits );
+ hsession.set_field( (HttpFieldIds)9, new std::string("via"), change_bits );
+ hsession.set_field( (HttpFieldIds)10, new std::string("response_code"), change_bits );
+ hsession.set_field( (HttpFieldIds)11, new std::string("server"), change_bits );
+ hsession.set_field( (HttpFieldIds)12, new std::string("xww"), change_bits );
+ hsession.set_field( (HttpFieldIds)13, new std::string("url"), change_bits );
const std::string* field;
field = hsession.get_field(REQ_AGENT_FID);
STRCMP_EQUAL(field->c_str(), "xww");
field = hsession.get_field(MISC_URL_FID);
STRCMP_EQUAL(field->c_str(), "url");
+
+ // Detect changes in host, url, user agent, response, and referer fields
+ // that generate appid event consumed by subscribers
+ CHECK_EQUAL(change_bits.test(APPID_HOST_BIT), true);
+ CHECK_EQUAL(change_bits.test(APPID_URL_BIT), true);
+ CHECK_EQUAL(change_bits.test(APPID_USERAGENT_BIT), true);
+ CHECK_EQUAL(change_bits.test(APPID_RESPONSE_BIT), true);
+ CHECK_EQUAL(change_bits.test(APPID_REFERER_BIT), true);
+}
+
+TEST(appid_http_session, change_bits_for_referred_appid)
+{
+ // Testing set_referred_payload_app_id_data
+ AppidChangeBits change_bits;
+ AppIdPegCounts::init_pegs();
+ session.service.set_id(APP_ID_HTTP);
+ session.scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
+ hsession.set_skip_simple_detect(false);
+ hsession.set_field( (HttpFieldIds)2, new std::string("referer"), change_bits );
+ hsession.process_http_packet(APP_ID_FROM_INITIATOR, change_bits);
+
+ // Detect changes in referred appid
+ CHECK_EQUAL(change_bits.test(APPID_REFERRED_BIT), true);
}
int main(int argc, char** argv)
}
}
-int AppIdHttpSession::process_http_packet(AppidSessionDirection) { return 0; }
+int AppIdHttpSession::process_http_packet(AppidSessionDirection, AppidChangeBits&) { return 0; }
char const* APPID_UT_XFF_IP_ADDR = "192.168.0.1";
char const* CONTENT_TYPE = "html/text";
#define URI_OFFSET 22
#define COOKIE_OFFSET 44
-void AppIdHttpSession::update_url()
+void AppIdHttpSession::update_url(AppidChangeBits&)
{
const std::string* host = meta_data[REQ_HOST_FID];
const std::string* uri = meta_data[REQ_URI_FID];
meta_offset[REQ_COOKIE_FID].second = COOKIE_OFFSET + strlen(NEW_COOKIE);
}
- void init_hsession_new_fields()
- {
- set_field(REQ_AGENT_FID, new std::string(USERAGENT));
- set_field(REQ_HOST_FID, new std::string(HOST));
- set_field(REQ_REFERER_FID, new std::string(REFERER));
- set_field(REQ_URI_FID, new std::string(URI));
- set_field(REQ_COOKIE_FID, new std::string(COOKIE));
- set_field(REQ_BODY_FID, new std::string(REQ_BODY));
- set_field(RSP_CONTENT_TYPE_FID, new std::string(CONTENT_TYPE));
- set_field(RSP_LOCATION_FID, new std::string(LOCATION));
- set_field(RSP_BODY_FID, new std::string(RSP_BODY));
- }
-
void reset()
{
for ( int i = 0; i < NUM_METADATA_FIELDS; i++)
{
common.flow_type = APPID_FLOW_TYPE_NORMAL;
service_port = APPID_UT_SERVICE_PORT;
+ AppidChangeBits change_bits;
client.update_user(APPID_UT_ID, APPID_UT_USERNAME);
- client.set_version(APPID_UT_CLIENT_VERSION);
+ client.set_version(APPID_UT_CLIENT_VERSION, change_bits);
service.set_vendor(APPID_UT_SERVICE_VENDOR);
- service.set_version(APPID_UT_SERVICE_VERSION);
+ service.set_version(APPID_UT_SERVICE_VERSION, change_bits);
subtype = &APPID_UT_SERVICE_SUBTYPE;
search_support_type = UNKNOWN_SEARCH_ENGINE;
tsession = new TlsSession;
- tsession->tls_host = (char*)APPID_UT_TLS_HOST;
service_ip.pton(AF_INET, APPID_UT_SERVICE_IP_ADDR);
common.initiator_ip.pton(AF_INET, APPID_UT_INITIATOR_IP_ADDR);
return data;
}
-void AppIdSession::set_application_ids(AppId, AppId, AppId, AppId) { }
+void AppIdSession::set_application_ids(AppId service_id, AppId client_id,
+ AppId payload_id, AppId misc_id, AppidChangeBits& change_bits)
+{
+ if (application_ids[APP_PROTOID_SERVICE] != service_id)
+ {
+ application_ids[APP_PROTOID_SERVICE] = service_id;
+ change_bits.set(APPID_SERVICE_BIT);
+ }
+ if (application_ids[APP_PROTOID_CLIENT] != client_id)
+ {
+ application_ids[APP_PROTOID_CLIENT] = client_id;
+ change_bits.set(APPID_CLIENT_BIT);
+ }
+ if (application_ids[APP_PROTOID_PAYLOAD] != payload_id)
+ {
+ application_ids[APP_PROTOID_PAYLOAD] = payload_id;
+ change_bits.set(APPID_PAYLOAD_BIT);
+ }
+ if (application_ids[APP_PROTOID_MISC] != misc_id)
+ {
+ application_ids[APP_PROTOID_MISC] = misc_id;
+ change_bits.set(APPID_MISC_BIT);
+ }
+}
AppId AppIdSession::pick_service_app_id()
{
- return APPID_UT_ID;
+ return service.get_id();
}
AppId AppIdSession::pick_misc_app_id()
{
- return APPID_UT_ID;
+ return misc_app_id;
}
AppId AppIdSession::pick_client_app_id()
{
- return APPID_UT_ID;
+ return client.get_id();
}
AppId AppIdSession::pick_payload_app_id()
{
- return APPID_UT_ID;
+ return payload.get_id();
}
AppId AppIdSession::pick_referred_payload_app_id()
TEST(appid_session_api, get_tls_host)
{
+ AppidChangeBits change_bits;
+ mock_session->tsession->set_tls_host(APPID_UT_TLS_HOST, 0, change_bits);
const char* val = appid_session_api->get_tls_host();
STRCMP_EQUAL(val, APPID_UT_TLS_HOST);
}
CHECK_TRUE(service == APPID_UT_ID);
CHECK_TRUE(!isLoginSuccessful);
mock_session->set_session_flags(APPID_SESSION_LOGIN_SUCCEEDED);
- val = appid_session_api->get_user_name(&service, &isLoginSuccessful);
+ appid_session_api->get_user_name(&service, &isLoginSuccessful);
CHECK_TRUE(service == APPID_UT_ID);
CHECK_TRUE(isLoginSuccessful);
}
void ServiceDiscovery::match_by_pattern(AppIdSession&, const Packet*, IpProtocol) {}
void ServiceDiscovery::get_port_based_services(IpProtocol, uint16_t, AppIdSession&) {}
void ServiceDiscovery::get_next_service(const Packet*, const AppidSessionDirection, AppIdSession&) {}
-int ServiceDiscovery::identify_service(AppIdSession&, Packet*, AppidSessionDirection) { return 0; }
+int ServiceDiscovery::identify_service(AppIdSession&, Packet*, AppidSessionDirection,
+ AppidChangeBits&) { return 0; }
int ServiceDiscovery::add_ftp_service_state(AppIdSession&) { return 0; }
-bool ServiceDiscovery::do_service_discovery(AppIdSession&, Packet*, AppidSessionDirection) { return 0; }
+bool ServiceDiscovery::do_service_discovery(AppIdSession&, Packet*, AppidSessionDirection,
+ AppidChangeBits&) { return 0; }
int ServiceDiscovery::incompatible_data(AppIdSession&, const Packet*,AppidSessionDirection,
ServiceDetector*) { return 0; }
int ServiceDiscovery::fail_service(AppIdSession&, const Packet*, AppidSessionDirection,
// Or, register observers with THirdPartyAppIDAttributeData and modify the
// set functions to copy the tp buffers directly into the appropriate observer.
static inline void process_http_session(AppIdSession& asd,
- ThirdPartyAppIDAttributeData& attribute_data)
+ ThirdPartyAppIDAttributeData& attribute_data, AppidChangeBits& change_bits)
{
AppIdHttpSession* hsession = asd.get_http_session();
string* field=0;
if ( hsession->get_field(MISC_URL_FID) )
hsession->set_chp_finished(false);
- hsession->set_field(MISC_URL_FID, url);
+ hsession->set_field(MISC_URL_FID, url, change_bits);
asd.scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
if (hsession->get_field(REQ_HOST_FID))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_HOST_FID, spdyRequestHost);
+ hsession->set_field(REQ_HOST_FID, spdyRequestHost, change_bits);
hsession->set_offset(REQ_HOST_FID,
attribute_data.spdy_request_host_begin(),
attribute_data.spdy_request_host_end());
if ( hsession->get_field(REQ_URI_FID) )
hsession->set_chp_finished(false);
- hsession->set_field(REQ_URI_FID, spdyRequestPath);
+ hsession->set_field(REQ_URI_FID, spdyRequestPath, change_bits);
hsession->set_offset(REQ_URI_FID,
attribute_data.spdy_request_path_begin(),
attribute_data.spdy_request_path_end());
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_HOST_FID, field);
+ hsession->set_field(REQ_HOST_FID, field, change_bits);
hsession->set_offset(REQ_HOST_FID,
attribute_data.http_request_host_begin(),
attribute_data.http_request_host_end());
// In all other cases field can be const string*.
field->insert(4, 1, 's');
}
- hsession->set_field(MISC_URL_FID, field);
+ hsession->set_field(MISC_URL_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_URI_FID, field);
+ hsession->set_field(REQ_URI_FID, field, change_bits);
hsession->set_offset(REQ_URI_FID,
attribute_data.http_request_uri_begin(),
attribute_data.http_request_uri_end());
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(MISC_VIA_FID, field);
+ hsession->set_field(MISC_VIA_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_VIA_FLAG;
}
else if ( (field=attribute_data.http_response_via(own)) != nullptr )
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(MISC_VIA_FID, field);
+ hsession->set_field(MISC_VIA_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_VIA_FLAG;
}
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_AGENT_FID, field);
+ hsession->set_field(REQ_AGENT_FID, field, change_bits);
hsession->set_offset(REQ_AGENT_FID,
attribute_data.http_request_user_agent_begin(),
attribute_data.http_request_user_agent_end());
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(MISC_RESP_CODE_FID, field);
+ hsession->set_field(MISC_RESP_CODE_FID, field, change_bits);
}
// Check to see if we've got an upgrade to HTTP/2 (if enabled).
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_REFERER_FID, field);
+ hsession->set_field(REQ_REFERER_FID, field, change_bits);
hsession->set_offset(REQ_REFERER_FID,
attribute_data.http_request_referer_begin(),
attribute_data.http_request_referer_end());
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_COOKIE_FID, field);
+ hsession->set_field(REQ_COOKIE_FID, field, change_bits);
hsession->set_offset(REQ_COOKIE_FID,
attribute_data.http_request_cookie_begin(),
attribute_data.http_request_cookie_end());
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(RSP_CONTENT_TYPE_FID, field);
+ hsession->set_field(RSP_CONTENT_TYPE_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_CONTENT_TYPE_FLAG;
}
if ( hsession->get_field(RSP_LOCATION_FID) )
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(RSP_LOCATION_FID, field);
+ hsession->set_field(RSP_LOCATION_FID, field, change_bits);
}
if ( (field=attribute_data.http_request_body(own)) != nullptr )
if ( hsession->get_field(REQ_BODY_FID) )
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(REQ_BODY_FID, field);
+ hsession->set_field(REQ_BODY_FID, field, change_bits);
}
if (hsession->get_ptype_scan_count(RSP_BODY_FID) &&
if (hsession->get_field(RSP_BODY_FID) )
if (!asd.get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->set_chp_finished(false);
- hsession->set_field(RSP_BODY_FID, field);
+ hsession->set_field(RSP_BODY_FID, field, change_bits);
}
if (attribute_data.numXffFields)
hsession->update_http_xff_address(attribute_data.xffFieldValue,
- attribute_data.numXffFields);
+ attribute_data.numXffFields, change_bits);
if (!hsession->is_chp_finished() || hsession->is_chp_hold_flow())
{
if ( (field=attribute_data.http_response_server(own)) != nullptr)
{
- hsession->set_field(MISC_SERVER_FID, field);
+ hsession->set_field(MISC_SERVER_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_VENDOR_FLAG;
}
if ( (field=attribute_data.http_request_x_working_with(own)) != nullptr )
{
- hsession->set_field(MISC_XWW_FID, field);
+ hsession->set_field(MISC_XWW_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_XWORKINGWITH_FLAG;
}
}
static inline void process_rtmp(AppIdSession& asd,
- ThirdPartyAppIDAttributeData& attribute_data, int confidence)
+ ThirdPartyAppIDAttributeData& attribute_data, int confidence, AppidChangeBits& change_bits)
{
AppIdHttpSession* hsession = asd.get_http_session();
AppId service_id = 0;
{
if ( ( field=attribute_data.http_request_url(own) ) != nullptr )
{
- hsession->set_field(MISC_URL_FID, field);
+ hsession->set_field(MISC_URL_FID, field, change_bits);
asd.scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
}
{
if ( ( field=attribute_data.http_request_referer(own) ) != nullptr )
{
- hsession->set_field(REQ_REFERER_FID, field);
+ hsession->set_field(REQ_REFERER_FID, field, change_bits);
}
}
{
if ( ( field=attribute_data.http_request_user_agent(own) ) != nullptr )
{
- hsession->set_field(REQ_AGENT_FID, field);
+ hsession->set_field(REQ_AGENT_FID, field, change_bits);
hsession->set_offset(REQ_AGENT_FID,
attribute_data.http_request_user_agent_begin(),
attribute_data.http_request_user_agent_end());
http_matchers->identify_user_agent(field->c_str(), size, service_id,
client_id, &version);
- asd.set_client_appid_data(client_id, version);
+ asd.set_client_appid_data(client_id, version, change_bits);
// do not overwrite a previously-set service
if ( service_id <= APP_ID_NONE )
- asd.set_service_appid_data(service_id, nullptr, nullptr);
+ asd.set_service_appid_data(service_id, nullptr, nullptr, change_bits);
asd.scan_flags |= ~SCAN_HTTP_USER_AGENT_FLAG;
snort_free(version);
{
// do not overwrite a previously-set client or service
if ( client_id <= APP_ID_NONE )
- asd.set_client_appid_data(client_id, nullptr);
+ asd.set_client_appid_data(client_id, nullptr, change_bits);
if ( service_id <= APP_ID_NONE )
- asd.set_service_appid_data(service_id, nullptr, nullptr);
+ asd.set_service_appid_data(service_id, nullptr, nullptr, change_bits);
// DO overwrite a previously-set data
- asd.set_payload_appid_data(payload_id, nullptr);
- asd.set_referred_payload_app_id_data(referred_payload_app_id);
+ asd.set_payload_appid_data(payload_id, nullptr, change_bits);
+ asd.set_referred_payload_app_id_data(referred_payload_app_id, change_bits);
}
}
}
static inline void process_ssl(AppIdSession& asd,
- ThirdPartyAppIDAttributeData& attribute_data)
+ ThirdPartyAppIDAttributeData& attribute_data, AppidChangeBits& change_bits)
{
AppId tmpAppId = APP_ID_NONE;
int tmpConfidence = 0;
asd.tsession = (TlsSession*)snort_calloc(sizeof(TlsSession));
if (!asd.client.get_id())
- asd.set_client_appid_data(APP_ID_SSL_CLIENT, nullptr);
+ asd.set_client_appid_data(APP_ID_SSL_CLIENT, nullptr, change_bits);
if ( (field=attribute_data.tls_host(false)) != nullptr )
{
- asd.tsession->set_tls_host(field->c_str(), field->size());
+ asd.tsession->set_tls_host(field->c_str(), field->size(), change_bits);
if (check_ssl_appid_for_reinspect(tmpAppId))
asd.scan_flags |= SCAN_SSL_HOST_FLAG;
}
}
static inline void process_third_party_results(AppIdSession& asd, int confidence,
- vector<AppId>& proto_list, ThirdPartyAppIDAttributeData& attribute_data)
+ vector<AppId>& proto_list, ThirdPartyAppIDAttributeData& attribute_data,
+ AppidChangeBits& change_bits)
{
if ( asd.payload.get_id() == APP_ID_NONE and contains(proto_list, APP_ID_EXCHANGE) )
asd.payload.set_id(APP_ID_EXCHANGE);
}
if (asd.get_session_flags(APPID_SESSION_HTTP_SESSION))
- process_http_session(asd, attribute_data);
+ process_http_session(asd, attribute_data, change_bits);
else if (contains(proto_list, APP_ID_RTMP) ||
contains(proto_list, APP_ID_RTSP) )
- process_rtmp(asd, attribute_data, confidence);
+ process_rtmp(asd, attribute_data, confidence, change_bits);
else if (contains(proto_list, APP_ID_SSL))
- process_ssl(asd, attribute_data);
+ process_ssl(asd, attribute_data, change_bits);
else if (contains(proto_list, APP_ID_FTP_CONTROL))
process_ftp_control(asd, attribute_data);
}
bool do_tp_discovery(AppIdSession& asd, IpProtocol protocol,
- Packet* p, AppidSessionDirection& direction)
+ Packet* p, AppidSessionDirection& direction, AppidChangeBits& change_bits)
{
if ( !TPLibHandler::have_tp() )
return true;
if ( app_info_flags & APPINFO_FLAG_TP_CLIENT )
asd.client.set_id(tp_app_id);
- process_third_party_results(asd, tp_confidence, tp_proto_list, tp_attribute_data);
+ process_third_party_results(asd, tp_confidence, tp_proto_list, tp_attribute_data,
+ change_bits);
if (asd.get_session_flags(APPID_SESSION_SSL_SESSION) &&
!(asd.scan_flags & SCAN_SSL_HOST_FLAG))
// Handle HTTP tunneling and SSL possibly then being used in that tunnel
if (tp_app_id == APP_ID_HTTP_TUNNEL)
- asd.set_payload_appid_data(APP_ID_HTTP_TUNNEL, NULL);
+ asd.set_payload_appid_data(APP_ID_HTTP_TUNNEL, NULL, change_bits);
else if ((asd.payload.get_id() == APP_ID_HTTP_TUNNEL) &&
(tp_app_id == APP_ID_SSL))
- asd.set_payload_appid_data(APP_ID_HTTP_SSL_TUNNEL, NULL);
+ asd.set_payload_appid_data(APP_ID_HTTP_SSL_TUNNEL, NULL, change_bits);
AppIdHttpSession* hsession = asd.get_http_session();
- hsession->process_http_packet(direction);
+ hsession->process_http_packet(direction, change_bits);
// If SSL over HTTP tunnel, make sure Snort knows that it's encrypted.
if (asd.payload.get_id() == APP_ID_HTTP_SSL_TUNNEL)
}
else if (asd.get_session_flags(APPID_SESSION_SSL_SESSION) && asd.tsession)
{
- asd.examine_ssl_metadata(p);
+ asd.examine_ssl_metadata(p, change_bits);
uint16_t serverPort;
AppId portAppId;
serverPort = (direction == APP_ID_FROM_INITIATOR) ? p->ptrs.dp : p->ptrs.sp;
class AppIdSession;
-bool do_tp_discovery(AppIdSession&, IpProtocol, snort::Packet*, AppidSessionDirection&);
+bool do_tp_discovery(AppIdSession&, IpProtocol, snort::Packet*, AppidSessionDirection&,
+ AppidChangeBits&);
#endif
set (PUB_SUB_INCLUDES
+ appid_events.h
expect_events.h
http_events.h
sip_events.h
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2017-2018 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.
+//--------------------------------------------------------------------------
+// appid_events.h author Masud Hasan <mashasan@cisco.com>
+
+#ifndef APPID_EVENTS_H
+#define APPID_EVENTS_H
+
+// This event conveys data published by the appid module to be consumed by data bus subscribers
+
+#include <bitset>
+
+#include "framework/data_bus.h"
+
+#define APPID_EVENT_ANY_CHANGE "appid_event_any_change"
+
+// Events are added as needed by subscribers
+// Any change here should also change change_bits_to_string()
+enum AppidChangeBit
+{
+ // id
+ APPID_SERVICE_BIT = 0,
+ APPID_CLIENT_BIT,
+ APPID_PAYLOAD_BIT,
+ APPID_MISC_BIT,
+ APPID_REFERRED_BIT,
+
+ // http
+ APPID_HOST_BIT,
+ APPID_TLSHOST_BIT,
+ APPID_URL_BIT,
+ APPID_USERAGENT_BIT,
+ APPID_RESPONSE_BIT,
+ APPID_REFERER_BIT,
+ APPID_XFF_BIT,
+
+ // other
+ APPID_VERSION_BIT,
+
+ APPID_MAX_BIT
+};
+
+typedef std::bitset<APPID_MAX_BIT> AppidChangeBits;
+
+inline void change_bits_to_string(AppidChangeBits& change_bits, std::string& str)
+{
+ size_t n = change_bits.count();
+
+ if (change_bits.test(APPID_SERVICE_BIT))
+ --n? str.append("service, ") : str.append("service");
+ if (change_bits.test(APPID_CLIENT_BIT))
+ --n? str.append("client, ") : str.append("client");
+ if (change_bits.test(APPID_PAYLOAD_BIT))
+ --n? str.append("payload, ") : str.append("payload");
+ if (change_bits.test(APPID_MISC_BIT))
+ --n? str.append("misc, ") : str.append("misc");
+ if (change_bits.test(APPID_REFERRED_BIT))
+ --n? str.append("referred, ") : str.append("referred");
+ if (change_bits.test(APPID_HOST_BIT))
+ --n? str.append("host, ") : str.append("host");
+ if (change_bits.test(APPID_TLSHOST_BIT))
+ --n? str.append("tls-host, ") : str.append("tls-host");
+ if (change_bits.test(APPID_URL_BIT))
+ --n? str.append("url, ") : str.append("url");
+ if (change_bits.test(APPID_USERAGENT_BIT))
+ --n? str.append("user-agent, ") : str.append("user-agent");
+ if (change_bits.test(APPID_RESPONSE_BIT))
+ --n? str.append("response, ") : str.append("response");
+ if (change_bits.test(APPID_REFERER_BIT))
+ --n? str.append("referrer, ") : str.append("referrer");
+ if (change_bits.test(APPID_XFF_BIT))
+ --n? str.append("xff, ") : str.append("xff");
+ if (change_bits.test(APPID_VERSION_BIT))
+ --n? str.append("client-version, ") : str.append("client-version");
+ if (n != 0) // make sure all bits from AppidChangeBit enum get translated
+ str.append("change_bits_to_string error!");
+}
+
+class AppidEvent : public snort::DataEvent
+{
+public:
+ AppidEvent(const AppidChangeBits& ac) : ac_bits(ac) {}
+
+ const AppidChangeBits& get_change_bitset()
+ { return ac_bits; }
+
+private:
+ const AppidChangeBits& ac_bits;
+};
+
+#endif