src/network_inspectors/Makefile \
src/network_inspectors/appid/Makefile \
src/network_inspectors/appid/test/Makefile \
-src/network_inspectors/appid/client_plugins/test/Makefile \
+src/network_inspectors/appid/detector_plugins/test/Makefile \
src/network_inspectors/appid/service_plugins/test/Makefile \
src/network_inspectors/arp_spoof/Makefile \
src/network_inspectors/binder/Makefile \
client_plugins/client_app_msn.cc
client_plugins/client_app_msn.h
client_plugins/client_app_rtp.cc
- client_plugins/client_app_smtp.cc
- client_plugins/client_app_smtp.h
client_plugins/client_app_ssh.cc
client_plugins/client_app_timbuktu.cc
client_plugins/client_app_tns.cc
service_plugins/service_rsync.h
service_plugins/service_rtmp.cc
service_plugins/service_rtmp.h
- service_plugins/service_smtp.cc
- service_plugins/service_smtp.h
service_plugins/service_snmp.cc
service_plugins/service_snmp.h
service_plugins/service_ssh.cc
detector_plugins/detector_pop3.cc
detector_plugins/detector_sip.cc
detector_plugins/detector_sip.h
+ detector_plugins/detector_smtp.cc
+ detector_plugins/detector_smtp.h
detector_plugins/http_url_patterns.cc
detector_plugins/http_url_patterns.h
)
target_include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
add_subdirectory(service_plugins/test)
-add_subdirectory(client_plugins/test)
+add_subdirectory(detector_plugins/test)
add_subdirectory(test)
#install (FILES ${APPID_INCLUDES}
client_plugins/client_app_msn.cc \
client_plugins/client_app_msn.h \
client_plugins/client_app_rtp.cc \
-client_plugins/client_app_smtp.cc \
-client_plugins/client_app_smtp.h \
client_plugins/client_app_ssh.cc \
client_plugins/client_app_timbuktu.cc \
client_plugins/client_app_tns.cc \
detector_plugins/detector_pop3.cc \
detector_plugins/detector_sip.cc \
detector_plugins/detector_sip.h \
+detector_plugins/detector_smtp.cc \
+detector_plugins/detector_smtp.h \
detector_plugins/http_url_patterns.cc \
detector_plugins/http_url_patterns.h
service_plugins/service_rsync.h \
service_plugins/service_rtmp.cc \
service_plugins/service_rtmp.h \
-service_plugins/service_smtp.cc \
-service_plugins/service_smtp.h \
service_plugins/service_snmp.cc \
service_plugins/service_snmp.h \
service_plugins/service_ssh.cc \
if ENABLE_UNIT_TESTS
SUBDIRS=test\
service_plugins/test \
-client_plugins/test
+detector_plugins/test
endif
uint16_t AppIdApi::get_http_uri_offset(AppIdSession* asd)
{
if (asd && asd->hsession)
- return asd->hsession->uriOffset;
+ return asd->hsession->fieldOffset[REQ_URI_FID];
return 0;
}
uint16_t AppIdApi::get_http_uri_end_offset(AppIdSession* asd)
{
if (asd && asd->hsession)
- return asd->hsession->uriEndOffset;
+ return asd->hsession->fieldEndOffset[REQ_URI_FID];
return 0;
}
uint16_t AppIdApi::get_http_cookie_offset(AppIdSession* asd)
{
if (asd && asd->hsession)
- return asd->hsession->cookieOffset;
+ return asd->hsession->fieldOffset[REQ_COOKIE_FID];
return 0;
}
uint16_t AppIdApi::get_http_cookie_end_offset(AppIdSession* asd)
{
if (asd && asd->hsession)
- return asd->hsession->cookieEndOffset;
+ return asd->hsession->fieldEndOffset[REQ_COOKIE_FID];
return 0;
}
+uint16_t getHttpFieldOffset(AppIdSession* asd, HTTP_FIELD_ID fieldId)
+{
+ if (asd && asd->hsession && fieldId >= 0 && fieldId <= HTTP_FIELD_MAX)
+ return asd->hsession->fieldOffset[fieldId];
+ return 0;
+}
+
+uint16_t getHttpFieldEndOffset(AppIdSession* asd, HTTP_FIELD_ID fieldId)
+{
+ if (asd && asd->hsession && fieldId >= 0 && fieldId <= HTTP_FIELD_MAX)
+ return asd->hsession->fieldEndOffset[fieldId];
+ return 0;
+}
+
SEARCH_SUPPORT_TYPE AppIdApi::get_http_search(AppIdSession* asd)
{
if (asd)
}
uint32_t AppIdApi::consume_ha_state(Flow* flow, const uint8_t* buf, uint8_t, IpProtocol proto,
- sfip_t* ip)
+ sfip_t* ip, uint16_t port)
{
AppIdSessionHA* appHA = (AppIdSessionHA*)buf;
if (appHA->flags & APPID_HA_FLAGS_APP)
if (!asd)
{
- asd = new AppIdSession(proto, ip);
+ asd = new AppIdSession(proto, ip, port);
flow->set_flow_data(asd);
+ asd->serviceAppId = appHA->appId[1];
if (asd->serviceAppId == APP_ID_FTP_CONTROL)
{
asd->set_session_flags(APPID_SESSION_CLIENT_DETECTED |
void free_smb_fp_data(AppIdSession*, FpSMBData*);
char* get_netbios_name(AppIdSession*);
uint32_t produce_ha_state(Flow* flow, uint8_t* buf);
- uint32_t consume_ha_state(Flow* flow, const uint8_t* buf, uint8_t length,
- IpProtocol proto, sfip_t* ip);
+ uint32_t consume_ha_state(Flow* flow, const uint8_t* buf, uint8_t length, IpProtocol proto,
+ sfip_t* ip, uint16_t initiatorPort);
AppIdSession* get_appid_data(Flow* flow);
char* get_dns_query(AppIdSession*, uint8_t* query_len);
uint16_t get_dns_query_offset(AppIdSession*);
uint32_t get_dns_ttl(AppIdSession*);
char* get_http_new_field(AppIdSession*, HTTP_FIELD_ID);
void free_http_new_field(AppIdSession*, HTTP_FIELD_ID);
+ uint16_t get_http_field_offset(AppIdSession*, HTTP_FIELD_ID);
+ uint16_t get_http_field_end_offset(AppIdSession*, HTTP_FIELD_ID);
};
SO_PUBLIC extern AppIdApi appid_api;
#include "thirdparty_appid_utils.h"
#include "utils/util.h"
-static void replace_header_data(char **data, const uint8_t *header_start,
- unsigned header_length)
+static void replace_header_data(char **data, uint16_t &datalen, const uint8_t *header_start,
+ int32_t header_length)
{
if(header_length <= 0)
return;
snort_free(*data);
*data = snort_strndup((char*)header_start, header_length);
+ datalen = header_length;
}
void HttpEventHandler::handle(DataEvent& event, Flow* flow)
{
AppIdSession* session;
int direction;
+ uint16_t tmplen;
const uint8_t* header_start;
- unsigned header_length;
+ int32_t header_length;
HttpEvent* http_event = (HttpEvent*)&event;
assert(flow);
header_start = http_event->get_host(header_length);
if(header_length > 0)
{
- replace_header_data(&session->hsession->host, header_start,
- header_length);
+ replace_header_data(&session->hsession->host,
+ session->hsession->host_buflen, header_start, header_length);
session->scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
header_start = http_event->get_uri(header_length);
- replace_header_data(&session->hsession->url, header_start,
- header_length);
+ if(header_length > 0)
+ {
+ replace_header_data(&session->hsession->uri,
+ session->hsession->uri_buflen, header_start,
+ header_length);
+
+ if(session->hsession->url)
+ snort_free(session->hsession->url);
+ tmplen = sizeof(HTTP_PREFIX) + session->hsession->host_buflen +
+ session->hsession->uri_buflen + 1;
+ session->hsession->url = (char*)snort_calloc(tmplen);
+ strcpy(session->hsession->url, HTTP_PREFIX);
+ strncat(session->hsession->url, session->hsession->host,
+ session->hsession->host_buflen);
+ strncat(session->hsession->url, session->hsession->uri,
+ session->hsession->uri_buflen);
+ }
}
header_start = http_event->get_user_agent(header_length);
if(header_length > 0)
{
- replace_header_data(&session->hsession->useragent, header_start,
+ replace_header_data(&session->hsession->useragent,
+ session->hsession->useragent_buflen, header_start,
header_length);
session->scan_flags |= SCAN_HTTP_USER_AGENT_FLAG;
}
+ header_start = http_event->get_cookie(header_length);
+ replace_header_data(&session->hsession->cookie,
+ session->hsession->cookie_buflen, header_start, header_length);
+
header_start = http_event->get_referer(header_length);
- replace_header_data(&session->hsession->referer, header_start,
- header_length);
+ replace_header_data(&session->hsession->referer,
+ session->hsession->referer_buflen, header_start, header_length);
header_start = http_event->get_x_working_with(header_length);
- replace_header_data(&session->hsession->x_working_with, header_start,
- header_length);
+ replace_header_data(&session->hsession->x_working_with, tmplen,
+ header_start, header_length);
+
+ // FIXIT-M: Should we get request body (may be expensive to copy)?
+ // It is not currently set in callback in 2.9.x, only via
+ // third-party.
}
else // Response headers.
{
header_start = http_event->get_content_type(header_length);
- replace_header_data(&session->hsession->content_type, header_start,
+ replace_header_data(&session->hsession->content_type,
+ session->hsession->content_type_buflen, header_start,
header_length);
+ header_start = http_event->get_location(header_length);
+ replace_header_data(&session->hsession->location,
+ session->hsession->location_buflen, header_start, header_length);
+
header_start = http_event->get_server(header_length);
- replace_header_data(&session->hsession->server, header_start,
+ replace_header_data(&session->hsession->server, tmplen, header_start,
header_length);
int32_t responseCodeNum = http_event->get_response_code();
{
snort_free(session->hsession->response_code);
session->hsession->response_code = snort_strdup(tmpstr);
+ session->hsession->response_code_buflen = strlen(tmpstr);
}
}
+
+ // FIXIT-M: Get Location header data.
+ // FIXIT-M: Should we get response body (may be expensive to copy)?
+ // It is not currently set in callback in 2.9.x, only via
+ // third-party.
}
// The Via header can be in both the request and response.
header_start = http_event->get_via(header_length);
if(header_length > 0)
{
- replace_header_data(&session->hsession->via, header_start,
+ replace_header_data(&session->hsession->via, tmplen, header_start,
header_length);
session->scan_flags |= SCAN_HTTP_VIA_FLAG;
}
session->set_session_flags(APPID_SESSION_SERVICE_DETECTED | APPID_SESSION_HTTP_SESSION);
if (direction == APP_ID_FROM_INITIATOR)
appid_stats.http_flows++;
- flow->set_application_ids(session->pick_service_app_id(),
- session->pick_client_app_id(), session->pick_payload_app_id(),
+ flow->set_application_ids(session->pick_service_app_id(),
+ session->pick_client_app_id(), session->pick_payload_app_id(),
session->pick_misc_app_id());
}
// FIXIT-M some of this stuff may be needed in some fashion...
#ifdef REMOVED_WHILE_NOT_IN_USE
_dpd.registerGeAppId(getOpenAppId);
- if (!thirdparty_appid_module)
- _dpd.streamAPI->register_http_header_callback(httpHeaderCallback);
_dpd.registerSslAppIdLookup(sslAppGroupIdLookup);
// FIXIT-M AppID will need to register for SIP events for sip detection to work...
const BaseApi* nin_appid = &appid_inspector_api.base;
#endif
-#ifdef REMOVED_WHILE_NOT_IN_USE
-// FIXIT-M This is to be replace with snort3 inspection events
-void httpHeaderCallback(Packet* p, HttpParsedHeaders* const headers)
-{
- AppIdSession* asd;
- int direction;
- AppIdConfig* pConfig = AppIdConfig::get_appid_config();
-
- if (thirdparty_appid_module)
- return;
- if (!p || !(asd = appid_api.get_appid_data(p->flow)))
- return;
-
- direction = p->is_from_client() ? APP_ID_FROM_INITIATOR : APP_ID_FROM_RESPONDER;
-
- if (!asd->hsession)
- asd->hsession = (decltype(asd->hsession))snort_calloc(sizeof(httpSession));
-
- if (direction == APP_ID_FROM_INITIATOR)
- {
- if (headers->host.start)
- {
- snort_free(asd->hsession->host);
- asd->hsession->host = snort_strndup((char*)headers->host.start, headers->host.len);
- asd->scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
-
- if (headers->url.start)
- {
- snort_free(asd->hsession->url);
- asd->hsession->url = (char*)snort_calloc(sizeof(HTTP_PREFIX) +
- headers->host.len + headers->url.len);
- strcpy(asd->hsession->url, HTTP_PREFIX);
- strncat(asd->hsession->url, (char*)headers->host.start, headers->host.len);
- strncat(asd->hsession->url, (char*)headers->url.start, headers->url.len);
- asd->scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
- }
- }
- if (headers->userAgent.start)
- {
- snort_free(asd->hsession->useragent);
- asd->hsession->useragent = snort_strndup((char*)headers->userAgent.start,
- headers->userAgent.len);
- asd->scan_flags |= SCAN_HTTP_USER_AGENT_FLAG;
- }
- if (headers->referer.start)
- {
- snort_free(asd->hsession->referer);
- asd->hsession->referer = snort_strndup((char*)headers->referer.start,
- headers->referer.len);
- }
- if (headers->via.start)
- {
- snort_free(asd->hsession->via);
- asd->hsession->via = snort_strndup((char*)headers->via.start, headers->via.len);
- asd->scan_flags |= SCAN_HTTP_VIA_FLAG;
- }
- }
- else
- {
- if (headers->via.start)
- {
- snort_free(asd->hsession->via);
- asd->hsession->via = snort_strndup((char*)headers->via.start, headers->via.len);
- asd->scan_flags |= SCAN_HTTP_VIA_FLAG;
- }
- if (headers->contentType.start)
- {
- snort_free(asd->hsession->content_type);
- asd->hsession->content_type = snort_strndup((char*)headers->contentType.start,
- headers->contentType.len);
- }
- if (headers->responseCode.start)
- {
- long responseCodeNum;
- responseCodeNum = strtoul((char*)headers->responseCode.start, nullptr, 10);
- if (responseCodeNum > 0 && responseCodeNum < 700)
- {
- snort_free(asd->hsession->response_code);
- asd->hsession->response_code = snort_strndup((char*)headers->responseCode.start,
- headers->responseCode.len);
- }
- }
- }
-
- asd->processHTTPPacket(p, direction, headers, pConfig);
- asd->set_session_flags(APPID_SESSION_SERVICE_DETECTED | APPID_SESSION_HTTP_SESSION);
- p->flow->set_application_ids(asd->pick_service_app_id(), asd->pick_client_app_id(),
- asd->pick_payload_app_id(), asd->pick_misc_app_id());
-}
-#endif
-
/**
* @returns 1 if some appid is found, 0 otherwise.
*/
THREAD_LOCAL AppIdFlowData* AppIdSession::fd_free_list = nullptr;
THREAD_LOCAL uint32_t AppIdSession::appid_flow_data_id = 0;
-// FIXIT-L - determine reason for this mapping and whether we still need it snort3 or can harmonize the IDs used
-static int16_t snortId_for_ftp;
+static int16_t snortId_for_unsynchronized;
static int16_t snortId_for_ftp_data;
-static int16_t snortId_for_imap;
-static int16_t snortId_for_pop3;
-static int16_t snortId_for_smtp;
static int16_t snortId_for_http2;
void map_app_names_to_snort_ids()
{
/* init globals for snortId compares */
- snortId_for_ftp = FindProtocolReference("ftp");
+ snortId_for_unsynchronized = AddProtocolReference("unsynchronized");
snortId_for_ftp_data = FindProtocolReference("ftp-data");
- snortId_for_imap = FindProtocolReference("imap");
- snortId_for_pop3 = FindProtocolReference("pop3");
- snortId_for_smtp = FindProtocolReference("smtp");
snortId_for_http2 = FindProtocolReference("http2");
}
return;
}
-// FIXIT-M this function does work that probably should be in http inspector, appid should leverage that if possible
-static inline void getOffsetsFromRebuilt(Packet* pkt, httpSession* hsession)
-{
-// size of "GET /\r\n\r\n"
- constexpr auto MIN_HTTP_REQ_HEADER_SIZE = sizeof("GET /\r\n\r\n");
- const uint8_t cookieStr[] = "Cookie: ";
- unsigned cookieStrLen = sizeof(cookieStr)-1;
- const uint8_t crlf[] = "\r\n";
- unsigned crlfLen = sizeof(crlf)-1;
- const uint8_t crlfcrlf[] = "\r\n\r\n";
- unsigned crlfcrlfLen = sizeof(crlfcrlf)-1;
- const uint8_t* p;
- uint8_t* headerEnd;
- uint16_t headerSize;
-
- if (!pkt || !pkt->data || pkt->dsize < MIN_HTTP_REQ_HEADER_SIZE)
- return;
-
- p = pkt->data;
-
- if (!(headerEnd = (uint8_t*)service_strstr(p, pkt->dsize, crlfcrlf, crlfcrlfLen)))
- return;
-
- headerEnd += crlfcrlfLen;
-
- headerSize = headerEnd - p;
-
- //uri offset is the index of the first char after the first space in the data
- if (!(p = (uint8_t*)memchr(pkt->data, ' ', headerSize)))
- return;
- hsession->uriOffset = ++p - pkt->data;
- headerSize = headerEnd - p;
-
- //uri end offset is the index of the first CRLF sequence after uri offset
- if (!(p = (uint8_t*)service_strstr(p, headerSize, crlf, crlfLen)))
- {
- // clear uri offset if we can't find an end offset
- hsession->uriOffset = 0;
- return;
- }
- hsession->uriEndOffset = p - pkt->data;
- headerSize = headerEnd - p;
-
- //cookie offset is the index of the first char after the cookie header, "Cookie: "
- if (!(p = (uint8_t*)service_strstr(p, headerSize, cookieStr, cookieStrLen)))
- return;
- hsession->cookieOffset = p + cookieStrLen - pkt->data;
- headerSize = headerEnd - p;
-
- //cookie end offset is the index of the first CRLF sequence after cookie offset
- if (!(p = (uint8_t*)service_strstr(p, headerSize, crlf, crlfLen)))
- {
- // clear cookie offset if we can't find a cookie end offset
- hsession->cookieOffset = 0;
- return;
- }
- hsession->cookieEndOffset = p - pkt->data;
-}
-
-
AppIdSession* AppIdSession::allocate_session(const Packet* p, IpProtocol proto, int direction)
{
const sfip_t* ip;
+ uint16_t port = 0;
ip = (direction == APP_ID_FROM_INITIATOR)
? p->ptrs.ip_api.get_src() : p->ptrs.ip_api.get_dst();
- AppIdSession* data = new AppIdSession(proto, ip);
-
if ( ( proto == IpProtocol::TCP || proto == IpProtocol::UDP ) && ( p->ptrs.sp != p->ptrs.dp ) )
- data->common.initiator_port =
- (direction == APP_ID_FROM_INITIATOR) ? p->ptrs.sp : p->ptrs.dp;
+ port = (direction == APP_ID_FROM_INITIATOR) ? p->ptrs.sp : p->ptrs.dp;
+
+ AppIdSession* data = new AppIdSession(proto, ip, port);
+
data->flow = p->flow;
data->stats.firstPktsecond = p->pkth->ts.tv_sec;
data->set_session_logging_state(p, direction);
-
+ data->snort_id = snortId_for_unsynchronized;
p->flow->set_flow_data(data);
return data;
}
-AppIdSession::AppIdSession(IpProtocol proto, const sfip_t* ip)
+AppIdSession::AppIdSession(IpProtocol proto, const sfip_t* ip, uint16_t port)
: FlowData(flow_id), protocol(proto)
{
service_ip.clear();
session_id = ++appid_flow_data_id;
common.flow_type = APPID_FLOW_TYPE_NORMAL;
common.initiator_ip = *ip;
+ common.initiator_port = port;
config = AppIdConfig::get_appid_config();
app_info_mgr = &AppInfoManager::get_instance();
if (thirdparty_appid_module)
assert(type != PktType::NONE);
- AppIdSession* asd = new AppIdSession(proto, cliIp);
+ // FIXIT-M - port parameter passed in as 0 since we may not know client port, verify this is correct
+ AppIdSession* asd = new AppIdSession(proto, cliIp, 0);
asd->common.policyId = appIdPolicyId;
// FIXIT-M expect session control packet support not ported to snort3 yet
// FIXIT-M - Need to convert this _dpd stream api call to the correct snort++ method
#ifdef REMOVED_WHILE_NOT_IN_USE
- bool is_http2 = _dpd.streamAPI->is_session_http2(p->flow);
+ bool is_http2 = false; // _dpd.streamAPI->is_session_http2(p->flow);
#else
bool is_http2 = false;
#endif
{
if ( p->is_rebuilt() && !p->flow->is_proxied() )
{
+ // FIXIT-M - latest 2.9 checks direction in this if statement below:
+ // ( (direction == APP_ID_FROM_INITIATOR) &&... ) do we need to add this?
if (asd && asd->hsession && asd->hsession->get_offsets_from_rebuilt)
{
- getOffsetsFromRebuilt(p, asd->hsession);
+ httpGetNewOffsetsFromPacket(p, asd->hsession);
if (asd->session_logging_enabled)
LogMessage(
"AppIdDbg %s offsets from rebuilt packet: uri: %u-%u cookie: %u-%u\n",
- asd->session_logging_id, asd->hsession->uriOffset,
- asd->hsession->uriEndOffset, asd->hsession->cookieOffset,
- asd->hsession->cookieEndOffset);
+ asd->session_logging_id,
+ asd->hsession->fieldOffset[REQ_URI_FID], asd->hsession->fieldEndOffset[REQ_URI_FID],
+ asd->hsession->fieldOffset[REQ_COOKIE_FID], asd->hsession->fieldEndOffset[REQ_COOKIE_FID]);
}
appid_stats.ignored_packets++;
return true;
static int ptype_scan_counts[NUMBER_OF_PTYPES];
+#ifdef REMOVED_WHILE_NOT_IN_USE
+static inline bool checkThirdPartyReinspect(const Packet* p, AppIdSession* asd)
+{
+ return p->dsize && !asd->get_session_flags(APPID_SESSION_NO_TPI) &&
+ asd->get_session_flags(APPID_SESSION_HTTP_SESSION) && TPIsAppIdDone(asd->tpsession);
+}
+
+#else
+static inline bool checkThirdPartyReinspect(const Packet*, AppIdSession*)
+{
+ return false;
+}
+#endif
+
#ifdef REMOVED_WHILE_NOT_IN_USE
void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence,
AppId* proto_list, ThirdPartyAppIDAttributeData* attribute_data)
if (get_session_flags(APPID_SESSION_SPDY_SESSION))
{
- if (attribute_data->spdyRequesHost)
- {
- if (session_logging_enabled)
- LogMessage("AppIdDbg %s SPDY host is %s\n", session_logging_id,
- attribute_data->spdyRequesHost);
- if (hsession->host)
- {
- snort_free(hsession->host);
- hsession->chp_finished = 0;
- }
- hsession->host = snort_strdup(attribute_data->spdyRequesHost);
- scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
- }
- if (attribute_data->spdyRequestPath)
- {
- if (session_logging_enabled)
- LogMessage("AppIdDbg %s SPDY URI is %s\n", session_logging_id,
- attribute_data->spdyRequestPath);
- if (hsession->uri)
- {
- snort_free(hsession->uri);
- hsession->chp_finished = 0;
- }
- hsession->uri = snort_strdup(attribute_data->spdyRequestPath);
- }
if (attribute_data->spdyRequestScheme &&
- attribute_data->spdyRequesHost &&
+ attribute_data->spdyRequestHost &&
attribute_data->spdyRequestPath)
{
static const char httpsScheme[] = "https";
}
size = strlen(scheme) +
- strlen(attribute_data->spdyRequesHost) +
+ strlen(attribute_data->spdyRequestHost) +
strlen(attribute_data->spdyRequestPath) +
sizeof("://"); // see sprintf() format
hsession->url = (char*)snort_calloc(size);
sprintf(hsession->url, "%s://%s%s",
- scheme, attribute_data->spdyRequesHost, attribute_data->spdyRequestPath);
+ scheme, attribute_data->spdyRequestHost, attribute_data->spdyRequestPath);
scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
+
+ snort_free(attribute_data->spdyRequestScheme);
+ attribute_data->spdyRequestScheme = nullptr;
}
- if (attribute_data->spdyRequestScheme)
+ else if (attribute_data->spdyRequestScheme)
{
snort_free(attribute_data->spdyRequestScheme);
attribute_data->spdyRequestScheme = nullptr;
}
- if (attribute_data->spdyRequesHost)
+
+ if (attribute_data->spdyRequestHost)
{
- snort_free(attribute_data->spdyRequesHost);
- attribute_data->spdyRequesHost = nullptr;
+ if (hsession->host)
+ {
+ snort_free(hsession->host);
+ hsession->chp_finished = 0;
+ }
+ hsession->host = attribute_data->spdyRequestHost;
+ attribute_data->spdyRequestHost = nullptr;
+ hsession->fieldOffset[REQ_HOST_FID] = attribute_data->spdyRequestHostOffset;
+ hsession->fieldEndOffset[REQ_HOST_FID] = attribute_data->spdyRequestHostEndOffset;
+ if(session_logging_enabled)
+ LogMessage("AppIdDbg %s SPDY Host (%u-%u) is %s\n", session_logging_id,
+ hsession->fieldOffset[REQ_HOST_FID], hsession->fieldEndOffset[REQ_HOST_FID], hsession->host);
+ scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
+
if (attribute_data->spdyRequestPath)
{
- snort_free(attribute_data->spdyRequestPath);
+ if (hsession->uri)
+ {
+ free(hsession->uri);
+ hsession->chp_finished = 0;
+ }
+ hsession->uri = attribute_data->spdyRequestPath;
attribute_data->spdyRequestPath = nullptr;
+ hsession->fieldOffset[REQ_URI_FID] = attribute_data->spdyRequestPathOffset;
+ hsession->fieldEndOffset[REQ_URI_FID] = attribute_data->spdyRequestPathEndOffset;
+ if(session_logging_enabled)
+ LogMessage("AppIdDbg %s SPDY URI (%u-%u) is %s\n", session_logging_id,
+ hsession->fieldOffset[REQ_URI_FID], hsession->fieldEndOffset[REQ_URI_FID], hsession->uri);
}
}
else
{
- if (attribute_data->httpRequesHost)
+ if (attribute_data->httpRequestHost)
{
- if (session_logging_enabled)
- LogMessage("AppIdDbg %s HTTP host is %s\n", session_logging_id,
- attribute_data->httpRequesHost);
if (hsession->host)
{
snort_free(hsession->host);
if (!get_session_flags(APPID_SESSION_APP_REINSPECT))
hsession->chp_finished = 0;
}
- hsession->host = attribute_data->httpRequesHost;
- attribute_data->httpRequesHost = nullptr;
+ hsession->host = attribute_data->httpRequestHost;
+ hsession->host_buflen = attribute_data->httpRequestHostLen;
+ hsession->fieldOffset[REQ_HOST_FID] = attribute_data->httpRequestHostOffset;
+ hsession->fieldEndOffset[REQ_HOST_FID] = attribute_data->httpRequestHostEndOffset;
+ attribute_data->httpRequestHost = nullptr;
+ if (session_logging_enabled)
+ LogMessage("AppIdDbg %s HTTP host is %s\n",
+ session_logging_id, attribute_data->httpRequestHost);
scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
- if (attribute_data->httpRequesUrl)
+ if (attribute_data->httpRequestUrl)
{
static const char httpScheme[] = "http://";
//change http to https if session was decrypted.
if (get_session_flags(APPID_SESSION_DECRYPTED)
&&
- memcmp(attribute_data->httpRequesUrl, httpScheme, sizeof(httpScheme)-1) == 0)
+ memcmp(attribute_data->httpRequestUrl, httpScheme, sizeof(httpScheme)-1) == 0)
{
- hsession->url = (char*)snort_calloc(strlen(attribute_data->httpRequesUrl) + 2);
+ hsession->url = (char*)snort_calloc(strlen(attribute_data->httpRequestUrl) + 2);
if (hsession->url)
sprintf(hsession->url, "https://%s",
- attribute_data->httpRequesUrl + sizeof(httpScheme)-1);
+ attribute_data->httpRequestUrl + sizeof(httpScheme)-1);
- snort_free(attribute_data->httpRequesUrl);
- attribute_data->httpRequesUrl = nullptr;
+ snort_free(attribute_data->httpRequestUrl);
+ attribute_data->httpRequestUrl = nullptr;
}
else
{
- hsession->url = attribute_data->httpRequesUrl;
- attribute_data->httpRequesUrl = nullptr;
+ hsession->url = attribute_data->httpRequestUrl;
+ attribute_data->httpRequestUrl = nullptr;
}
scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
hsession->chp_finished = 0;
}
hsession->uri = attribute_data->httpRequestUri;
- hsession->uriOffset = attribute_data->httpRequestUriOffset;
- hsession->uriEndOffset = attribute_data->httpRequestUriEndOffset;
+ hsession->uri_buflen = attribute_data->httpRequestUriLen;
+ hsession->fieldOffset[REQ_URI_FID] = attribute_data->httpRequestUriOffset;
+ hsession->fieldEndOffset[REQ_URI_FID] = attribute_data->httpRequestUriEndOffset;
attribute_data->httpRequestUri = nullptr;
- attribute_data->httpRequestUriOffset = 0;
- attribute_data->httpRequestUriEndOffset = 0;
if (session_logging_enabled)
LogMessage("AppIdDbg %s uri (%u-%u) is %s\n", session_logging_id,
- hsession->uriOffset, hsession->uriEndOffset,
- hsession->uri);
+ hsession->fieldOffset[REQ_URI_FID], hsession->fieldEndOffset[REQ_URI_FID],
+ hsession->uri);
}
}
if (attribute_data->httpRequestVia)
hsession->chp_finished = 0;
}
hsession->response_code = attribute_data->httpResponseCode;
+ hsession->response_code_buflen = attribute_data->httpResponseCodeLen;
attribute_data->httpResponseCode = nullptr;
}
// Check to see if we've got an upgrade to HTTP/2 (if enabled).
snort_free(attribute_data->httpResponseUpgrade);
attribute_data->httpResponseUpgrade = nullptr;
}
- if (!config->mod_config->referred_appId_disabled &&
- attribute_data->httpRequestReferer)
+ if (attribute_data->httpRequestReferer)
{
if (session_logging_enabled)
LogMessage("AppIdDbg %s referrer is %s\n", session_logging_id,
hsession->chp_finished = 0;
}
hsession->referer = attribute_data->httpRequestReferer;
+ hsession->referer_buflen = attribute_data->httpRequestRefererLen;
attribute_data->httpRequestReferer = nullptr;
+ hsession->fieldOffset[REQ_REFERER_FID] = attribute_data->httpRequestRefererOffset;
+ hsession->fieldEndOffset[REQ_REFERER_FID] = attribute_data->httpRequestRefererEndOffset;
+ if (session_logging_enabled)
+ LogMessage("AppIdDbg %s Referer (%u-%u) is %s\n", session_logging_id,
+ hsession->fieldOffset[REQ_REFERER_FID], hsession->fieldEndOffset[REQ_REFERER_FID],
+ hsession->referer);
}
+
if (attribute_data->httpRequestCookie)
{
if (hsession->cookie)
hsession->chp_finished = 0;
}
hsession->cookie = attribute_data->httpRequestCookie;
- hsession->cookieOffset = attribute_data->httpRequestCookieOffset;
- hsession->cookieEndOffset = attribute_data->httpRequestCookieEndOffset;
+ hsession->cookie_buflen = attribute_data->httpRequestCookieLen;
+ hsession->fieldOffset[REQ_COOKIE_FID] = attribute_data->httpRequestCookieOffset;
+ hsession->fieldEndOffset[REQ_COOKIE_FID] = attribute_data->httpRequestCookieEndOffset;
attribute_data->httpRequestCookie = nullptr;
attribute_data->httpRequestCookieOffset = 0;
attribute_data->httpRequestCookieEndOffset = 0;
if (session_logging_enabled)
LogMessage("AppIdDbg %s cookie (%u-%u) is %s\n", session_logging_id,
- hsession->cookieOffset, hsession->cookieEndOffset,
- hsession->cookie);
+ hsession->fieldOffset[REQ_COOKIE_FID], hsession->fieldEndOffset[REQ_COOKIE_FID],
+ hsession->cookie);
}
if (attribute_data->httpResponseContent)
{
hsession->chp_finished = 0;
}
hsession->content_type = attribute_data->httpResponseContent;
+ hsession->content_type_buflen = attribute_data->httpResponseContentLen;
attribute_data->httpResponseContent = nullptr;
scan_flags |= SCAN_HTTP_CONTENT_TYPE_FLAG;
}
hsession->chp_finished = 0;
}
hsession->location = attribute_data->httpResponseLocation;
+ hsession->location_buflen = attribute_data->httpResponseLocationLen;
attribute_data->httpResponseLocation = nullptr;
}
if (attribute_data->httpRequestBody)
hsession->chp_finished = 0;
}
hsession->req_body = attribute_data->httpRequestBody;
+ hsession->req_body_buflen = attribute_data->httpRequestBodyLen;
attribute_data->httpRequestBody = nullptr;
}
if (ptype_scan_counts[BODY_PT] && attribute_data->httpResponseBody)
hsession->chp_finished = 0;
}
hsession->body = attribute_data->httpResponseBody;
+ hsession->body_buflen = attribute_data->httpResponseBodyLen;
attribute_data->httpResponseBody = nullptr;
}
if (attribute_data->numXffFields)
if (!hsession->url)
{
- if (attribute_data->httpRequesUrl)
+ if (attribute_data->httpRequestUrl)
{
- hsession->url = attribute_data->httpRequesUrl;
- attribute_data->httpRequesUrl = nullptr;
+ hsession->url = attribute_data->httpRequestUrl;
+ attribute_data->httpRequestUrl = nullptr;
scan_flags |= SCAN_HTTP_HOST_URL_FLAG;
}
}
if (p->dsize || config->mod_config->tp_allow_probes)
{
- if (protocol != IpProtocol::TCP || !p->dsize || (p->packet_flags & PKT_STREAM_ORDER_OK)
- || config->mod_config->tp_allow_probes)
+ if (protocol != IpProtocol::TCP || (p->packet_flags & PKT_STREAM_ORDER_OK)
+ || config->mod_config->tp_allow_probes)
{
+
+ Profile tpLibPerfStats_profile_context(tpLibPerfStats);
+ if (!tpsession)
{
- Profile tpLibPerfStats_profile_context(tpLibPerfStats);
- if (!tpsession)
- {
- if (!(tpsession = thirdparty_appid_module->session_create()))
- FatalError("Could not allocate tpsession data");
- }; // debug output of packet content
- thirdparty_appid_module->session_process(tpsession, p, direction, &tp_app_id, &tp_confidence,
- &tp_proto_list, &tp_attribute_data);
- }
+ if (!(tpsession = thirdparty_appid_module->session_create()))
+ FatalError("Could not allocate tpsession data");
+ }; // debug output of packet content
+ thirdparty_appid_module->session_process(tpsession, p, direction, &tp_app_id, &tp_confidence,
+ &tp_proto_list, &tp_attribute_data);
+
isTpAppidDiscoveryDone = true;
if (thirdparty_appid_module->session_state_get(tpsession) == TP_STATE_CLASSIFIED)
clear_session_flags(APPID_SESSION_APP_REINSPECT);
if (session_logging_enabled)
LogMessage("AppIdDbg %s 3rd party returned %d\n", session_logging_id, tp_app_id);
- if (app_info_mgr->get_app_info_flags(tp_app_id, APPINFO_FLAG_IGNORE))
- {
- if (session_logging_enabled)
- LogMessage("AppIdDbg %s 3rd party ignored\n", session_logging_id);
-
- if (get_session_flags(APPID_SESSION_HTTP_SESSION))
- tp_app_id = APP_ID_HTTP;
- else
- tp_app_id = APP_ID_NONE;
- }
// For now, third party can detect HTTP/2 (w/o metadata) for
// some cases. Treat it like HTTP w/ is_http2 flag set.
if ((tp_app_id == APP_ID_HTTP2) && (tp_confidence == 100))
client_app_id = tp_app_id;
ProcessThirdPartyResults(p, tp_confidence, tp_proto_list, tp_attribute_data);
+
+ if (get_session_flags(APPID_SESSION_SSL_SESSION) &&
+ !(scan_flags & SCAN_SSL_HOST_FLAG))
+ {
+ setSSLSquelch(p, 1, tp_app_id);
+ }
+
+ if (app_info_mgr->get_app_info_flags(tp_app_id, APPINFO_FLAG_IGNORE))
+ {
+ if (session_logging_enabled)
+ LogMessage("AppIdDbg %s 3rd party ignored\n", session_logging_id);
+
+ if (get_session_flags(APPID_SESSION_HTTP_SESSION))
+ tp_app_id = APP_ID_HTTP;
+ else
+ tp_app_id = APP_ID_NONE;
+ }
}
else
{
LogMessage("AppIdDbg %s 3rd party packet out-of-order\n", session_logging_id);
}
}
+
if (thirdparty_appid_module->session_state_get(tpsession) == TP_STATE_MONITORING)
{
thirdparty_appid_module->disable_flags(tpsession,
TP_SESSION_FLAG_ATTRIBUTE | TP_SESSION_FLAG_TUNNELING | TP_SESSION_FLAG_FUTUREFLOW);
}
+
if (tp_app_id == APP_ID_SSL &&
(Stream::get_application_protocol_id(p->flow) == snortId_for_ftp_data))
{
// to APP_ID_NONE so the FTP preprocessor picks up the flow.
tp_app_id = APP_ID_NONE;
}
+
if (tp_app_id > APP_ID_NONE
&& (!get_session_flags(APPID_SESSION_APP_REINSPECT) || payload_app_id > APP_ID_NONE))
{
tp_payload_app_id = tp_app_id;
tp_app_id = APP_ID_HTTP;
+ // Handle HTTP tunneling and SSL possibly then being used in that tunnel
+ if (tp_app_id == APP_ID_HTTP_TUNNEL)
+ set_payload_app_id_data(APP_ID_HTTP_TUNNEL, NULL);
+ if ((payload_app_id == APP_ID_HTTP_TUNNEL) && (tp_app_id == APP_ID_SSL))
+ set_payload_app_id_data(APP_ID_HTTP_SSL_TUNNEL, NULL);
+
processHTTPPacket(p, direction, nullptr);
+
+ // If SSL over HTTP tunnel, make sure Snort knows that it's encrypted.
+ if (payload_app_id == APP_ID_HTTP_SSL_TUNNEL)
+ snort_app_id = APP_ID_SSL;
+
if (TPIsAppIdAvailable(tpsession) && tp_app_id == APP_ID_HTTP
&& !get_session_flags(APPID_SESSION_APP_REINSPECT))
{
if (tp_app_id == APP_ID_SSL)
{
tp_app_id = porAppId;
- //SSL policy needs to determine IMAPS/POP3S etc before appId sees first
- // server packet
+ //SSL policy determines IMAPS/POP3S etc before appId sees first server packet
portServiceAppId = porAppId;
if (session_logging_enabled)
LogMessage("AppIdDbg %s SSL is service %d, portServiceAppId %d\n", session_logging_id,
}
else
{
- if (protocol != IpProtocol::TCP || !p->dsize
- || (p->packet_flags & (PKT_STREAM_ORDER_OK | PKT_STREAM_ORDER_BAD)))
+ if (protocol != IpProtocol::TCP ||
+ (p->packet_flags & (PKT_STREAM_ORDER_OK | PKT_STREAM_ORDER_BAD)))
{
if (direction == APP_ID_FROM_INITIATOR)
{
{
if (!asd)
{
+ uint16_t port = 0;
+
ip = (direction == APP_ID_FROM_INITIATOR) ?
p->ptrs.ip_api.get_src() : p->ptrs.ip_api.get_dst();
- AppIdSession* tmp_session = new AppIdSession(protocol, ip);
+ if ((protocol == IpProtocol::TCP || protocol == IpProtocol::UDP)
+ && p->ptrs.sp != p->ptrs.dp)
+ {
+ port = (direction == APP_ID_FROM_INITIATOR) ? p->ptrs.sp : p->ptrs.dp;
+ }
+
+ AppIdSession* tmp_session = new AppIdSession(protocol, ip, port);
if ((flow_flags & APPID_SESSION_BIDIRECTIONAL_CHECKED) ==
APPID_SESSION_BIDIRECTIONAL_CHECKED)
else
tmp_session->common.flow_type = APPID_FLOW_TYPE_TMP;
tmp_session->common.flags = flow_flags;
- tmp_session->common.initiator_ip = *ip;
- if ((protocol == IpProtocol::TCP || protocol == IpProtocol::UDP)
- && p->ptrs.sp != p->ptrs.dp)
- {
- tmp_session->common.initiator_port =
- (direction == APP_ID_FROM_INITIATOR) ? p->ptrs.sp : p->ptrs.dp;
- }
- else
- tmp_session->common.initiator_port = 0;
tmp_session->common.policyId = appIdPolicyId;
p->flow->set_flow_data(tmp_session);
}
asd->check_app_detection_restart();
//restart inspection by 3rd party
- if (!asd->get_session_flags(APPID_SESSION_NO_TPI))
+ if (!asd->tp_reinspect_by_initiator && (direction == APP_ID_FROM_INITIATOR) && checkThirdPartyReinspect(p, asd))
{
- if (TPIsAppIdDone(asd->tpsession) && asd->get_session_flags(
- APPID_SESSION_HTTP_SESSION) && p->dsize)
- {
- if (asd->tp_reinspect_by_initiator)
- {
- asd->clear_session_flags(APPID_SESSION_APP_REINSPECT);
- if (direction == APP_ID_FROM_RESPONDER)
- asd->tp_reinspect_by_initiator = 0; //toggle at OK response
- }
- else if (direction == APP_ID_FROM_INITIATOR)
- {
- asd->tp_reinspect_by_initiator = 1; //once per request
- asd->set_session_flags(APPID_SESSION_APP_REINSPECT);
- if (asd->session_logging_enabled)
- LogMessage("AppIdDbg %s 3rd party allow reinspect http\n",
- asd->session_logging_id);
- asd->clear_http_field();
- }
- }
+ asd->tp_reinspect_by_initiator = true;
+ asd->set_session_flags(APPID_SESSION_APP_REINSPECT);
+ if (asd->session_logging_enabled)
+ LogMessage("AppIdDbg %s 3rd party allow reinspect http\n",
+ asd->session_logging_id);
+ asd->clear_http_field();
}
if (asd->tp_app_id == APP_ID_SSH && asd->payload_app_id != APP_ID_SFTP &&
isTpAppidDiscoveryDone = asd->do_third_party_discovery(protocol, ip, p, direction);
#endif
- if (direction == APP_ID_FROM_RESPONDER && !asd->get_session_flags(
- APPID_SESSION_PORT_SERVICE_DONE|APPID_SESSION_SYN_RST))
+ if ( asd->tp_reinspect_by_initiator && checkThirdPartyReinspect(p, asd) )
{
- asd->set_session_flags(APPID_SESSION_PORT_SERVICE_DONE);
- asd->portServiceAppId = getPortServiceId(protocol, p->ptrs.sp, asd->config);
- if (asd->session_logging_enabled)
- LogMessage("AppIdDbg %s port service %d\n", asd->session_logging_id,
- asd->portServiceAppId);
+ asd->clear_session_flags(APPID_SESSION_APP_REINSPECT);
+ if (direction == APP_ID_FROM_RESPONDER)
+ asd->tp_reinspect_by_initiator = false; //toggle at OK response
+ }
+
+ if ( !asd->get_session_flags(APPID_SESSION_PORT_SERVICE_DONE) )
+ {
+ switch (protocol)
+ {
+ case IpProtocol::TCP:
+ if (asd->get_session_flags(APPID_SESSION_SYN_RST)) // TCP-specific exception
+ break;
+ // fall through to next test
+ case IpProtocol::UDP:
+ // Both TCP and UDP need this test to be made
+ // against only the p->src_port of the response.
+ // For all other cases the port parameter is never checked.
+ if (direction != APP_ID_FROM_RESPONDER)
+ break;
+ // fall through to all other cases
+ // All protocols other than TCP and UDP come straight here.
+ default:
+ {
+ asd->portServiceAppId = getPortServiceId(protocol, p->ptrs.sp, asd->config);
+ if (asd->session_logging_enabled)
+ LogMessage("AppIdDbg %s port service %d\n",
+ asd->session_logging_id, asd->portServiceAppId);
+ asd->set_session_flags(APPID_SESSION_PORT_SERVICE_DONE);
+ }
+ break;
+ }
}
/* Length-based detectors. */
else if (asd->get_session_flags(APPID_SESSION_SSL_SESSION) && asd->tsession)
asd->examine_ssl_metadata(p);
}
+ // FIXIT-M - snort 2.x has added a check for midstream pickup to this if, do we need that?
else if (protocol != IpProtocol::TCP || !p->dsize || (p->packet_flags & PKT_STREAM_ORDER_OK))
{
// FIXIT-M commented out assignment causes analysis warning
void AppIdSession::sync_with_snort_id(AppId newAppId, Packet* p)
{
- AppInfoTableEntry* entry;
- int16_t tempSnortId = snort_id;
-
- if (tempSnortId == UNSYNCED_SNORT_ID)
- tempSnortId = snort_id = p->flow->ssn_state.application_protocol;
+ if (newAppId > APP_ID_NONE && newAppId < SF_APPID_MAX)
+ {
+ // Certain AppIds are not useful to identifying snort preprocessor choices
+ switch (newAppId)
+ {
+ case APP_ID_FTPS:
+ case APP_ID_FTPSDATA:
+
+ // These all are variants of HTTPS
+ case APP_ID_DDM_SSL:
+ case APP_ID_MSFT_GC_SSL:
+ case APP_ID_NSIIOPS:
+ case APP_ID_SF_APPLIANCE_MGMT:
+ case APP_ID_HTTPS:
+
+ case APP_ID_IMAPS:
+ case APP_ID_IRCS:
+ case APP_ID_LDAPS:
+ case APP_ID_NNTPS:
+ case APP_ID_POP3S:
+ case APP_ID_SMTPS:
+ case APP_ID_SSHELL:
+ case APP_ID_TELNETS:
+ return;
- if (tempSnortId == snortId_for_ftp || tempSnortId == snortId_for_ftp_data ||
- tempSnortId == snortId_for_imap || tempSnortId == snortId_for_pop3 ||
- tempSnortId == snortId_for_smtp || tempSnortId == snortId_for_http2)
- {
- return; // These preprocessors, in snort proper, already know and expect these to remain
- // unchanged.
- }
- if ((entry = app_info_mgr->get_app_info_entry(newAppId)) && (tempSnortId = entry->snortId))
- {
- // Snort has a separate protocol ID for HTTP/2. We don't. So, when we
- // talk to them about it, we have to play by their rules.
- if ((newAppId == APP_ID_HTTP) && (is_http2))
- tempSnortId = snortId_for_http2;
+ case APP_ID_HTTP:
+ if (is_http2)
+ newAppId = APP_ID_HTTP2;
+ break;
+ default:
+ break;
+ }
- if (tempSnortId != snort_id)
+ AppInfoTableEntry *entry = app_info_mgr->get_app_info_entry(newAppId);
+ if ( entry )
{
- if (session_logging_enabled)
- if (tempSnortId == snortId_for_http2)
- LogMessage("AppIdDbg %s Telling Snort that it's HTTP/2\n",
- session_logging_id);
+ int16_t tempSnortId = entry->snortId;
+ // A particular APP_ID_xxx may not be assigned a service_snort_key value
+ // in the rna_app.yaml file entry; so ignore the tempSnortId == 0 case.
+ if( tempSnortId == 0 && (newAppId == APP_ID_HTTP2))
+ tempSnortId = snortId_for_http2;
+
+ if ( tempSnortId != snort_id )
+ {
+ snort_id = tempSnortId;
+ if (session_logging_enabled)
+ if (tempSnortId == snortId_for_http2)
+ LogMessage("AppIdDbg %s Telling Snort that it's HTTP/2\n",
+ session_logging_id);
- p->flow->ssn_state.application_protocol = tempSnortId;
- snort_id = tempSnortId;
+ p->flow->ssn_state.application_protocol = tempSnortId;
+ }
}
}
}
clear_http_field();
- for (i = 0; i < NUMBER_OF_PTYPES; i++)
- {
- if (nullptr != hsession->new_field[i])
+ if (hsession->new_field_contents)
+ for (i = 0; i < NUMBER_OF_PTYPES; i++)
{
- snort_free(hsession->new_field[i]);
- hsession->new_field[i] = nullptr;
+ if (nullptr != hsession->new_field[i])
+ {
+ snort_free(hsession->new_field[i]);
+ hsession->new_field[i] = nullptr;
+ }
}
- }
if (hsession->fflow)
{
snort_free(hsession->fflow);
thirdparty_appid_module->session_delete(tpsession, 1);
}
-int AppIdSession::initial_CHP_sweep(char** chp_buffers, MatchedCHPAction** ppmatches)
+int AppIdSession::initial_CHP_sweep(char** chp_buffers, uint16_t* chp_buffer_lengths, MatchedCHPAction** ppmatches)
{
CHPApp* cah = nullptr;
int longest = 0;
- int size, i;
CHPTallyAndActions chp;
chp.matches = *ppmatches;
- for (i = 0; i <= MAX_KEY_PATTERN; i++)
+ for (unsigned i = 0; i <= MAX_KEY_PATTERN; i++)
{
ppmatches[i] = nullptr;
- if (chp_buffers[i] && (size = strlen(chp_buffers[i])))
- scan_key_chp((PatternType)i, chp_buffers[i], size, chp);
+ if (chp_buffers[i] && chp_buffer_lengths[i])
+ scan_key_chp((PatternType)i, chp_buffers[i], chp_buffer_lengths[i], chp);
}
if (chp.match_tally.empty())
return 0;
{
// We were planning to pass along the content of ppmatches to the second phase and let
// them be freed inside scanCHP, but we have no candidate so we free here
- for (i = 0; i <= MAX_KEY_PATTERN; i++)
+ for (unsigned i = 0; i <= MAX_KEY_PATTERN; i++)
{
if (ppmatches[i])
{
candidate has been chosen and it is pointed to by cah
we will preserve any match sets until the calls to scanCHP()
***************************************************************/
- for (i = 0; i < NUMBER_OF_PTYPES; i++)
+ for (unsigned i = 0; i < NUMBER_OF_PTYPES; i++)
{
ptype_scan_counts[i] = cah->ptype_scan_counts[i];
hsession->ptype_req_counts[i] = cah->ptype_req_counts[i] +
void AppIdSession::processCHP(char** version, Packet* p)
{
- int i, size;
+ int i;
int found_in_buffer = 0;
char* user = nullptr;
AppId chp_final;
http_session->body,
};
+ uint16_t chp_buffer_lengths[NUMBER_OF_PTYPES] = {
+ http_session->useragent_buflen,
+ http_session->host_buflen,
+ http_session->referer_buflen,
+ http_session->uri_buflen,
+ http_session->cookie_buflen,
+ http_session->req_body_buflen,
+ http_session->content_type_buflen,
+ http_session->location_buflen,
+ http_session->body_buflen,
+ };
+
char* chp_rewritten[NUMBER_OF_PTYPES] =
{
nullptr,nullptr,nullptr,
}
}
- if (!initial_CHP_sweep(chp_buffers, chp_matches))
+ if (!initial_CHP_sweep(chp_buffers, chp_buffer_lengths, chp_matches))
http_session->chp_finished = 1; // this is a failure case.
}
+
if (!http_session->chp_finished && http_session->chp_candidate)
{
for (i = 0; i < NUMBER_OF_PTYPES; i++)
{
- if (ptype_scan_counts[i] && chp_buffers[i] && (size = strlen(chp_buffers[i])) > 0)
+ if ( !ptype_scan_counts[i] )
+ continue;
+
+ if ( chp_buffers[i] && chp_buffer_lengths[i] )
{
found_in_buffer = 0;
- ret = scan_chp((PatternType)i, chp_buffers[i], size, chp_matches[i], version, &user,
- &chp_rewritten[i], &found_in_buffer, http_session, p);
+ ret = scan_chp((PatternType)i, chp_buffers[i], chp_buffer_lengths[i], chp_matches[i], version, &user,
+ &chp_rewritten[i], &found_in_buffer, http_session, p);
chp_matches[i] = nullptr; // freed by scanCHP()
http_session->total_found += found_in_buffer;
- http_session->num_scans--;
- ptype_scan_counts[i] = 0;
- // Give up if scanCHP returns nothing, OR
- // (if we did not match the right numbher of patterns in this field AND EITHER
- // (there is no match quota [all must match]) OR
- // (the total number of matches is less than our match quota))
- if (!ret ||
- (found_in_buffer < http_session->ptype_req_counts[i] &&
- (!http_session->num_matches ||
- http_session->total_found < http_session->num_matches)))
+ if (!ret || found_in_buffer < http_session->ptype_req_counts[i])
{
- http_session->chp_candidate = 0;
- break;
+ // No match at all or the required matches for the field was NOT made
+ if (!http_session->num_matches)
+ {
+ // num_matches == 0 means: all must succeed
+ // give up early
+ http_session->chp_candidate = 0;
+ break;
+ }
}
- /* We are finished if we have a num_matches target and we've met it or
- if we have done all the scans */
- if (!http_session->num_scans ||
- (http_session->num_matches && http_session->total_found >=
- http_session->num_matches))
+ }
+ else
+ {
+ if (!http_session->num_matches)
{
- http_session->chp_finished = 1;
+ // num_matches == 0 means: all must succeed give up early
+ http_session->chp_candidate = 0;
break;
}
}
- else if (ptype_scan_counts[i] && !http_session->chp_hold_flow)
+
+ // Decrement the expected scan count toward 0.
+ ptype_scan_counts[i] = 0;
+ http_session->num_scans--;
+ // if we have reached the end of the list of scans (which have something to do), then num_scans == 0
+ if (http_session->num_scans == 0)
{
- /* we have a scan count, but nothing in the buffer, so we should drop out of CHP */
- http_session->chp_candidate = 0;
+ // we finished the last scan
+ // either the num_matches value was zero and we failed early-on or we need to check for the min.
+ if (http_session->num_matches &&
+ http_session->total_found < http_session->num_matches)
+ {
+ // There was a minimum scans match count (num_matches != 0)
+ // And we did not reach that minimum
+ http_session->chp_candidate = 0;
+ break;
+ }
+ // All required matches were met.
+ http_session->chp_finished = 1;
break;
}
}
+
if (!http_session->chp_candidate)
{
http_session->chp_finished = 1;
}
if (http_session->chp_candidate && http_session->chp_finished)
{
- chp_final = http_session->chp_alt_candidate ?
- http_session->chp_alt_candidate :
- http_session->chp_candidate >> CHP_APPID_BITS_FOR_INSTANCE; // transform the
- // instance into the
- // appId.
+ chp_final = http_session->chp_alt_candidate ? http_session->chp_alt_candidate :
+ CHP_APPIDINSTANCE_TO_ID(http_session->chp_candidate);
+
if (http_session->app_type_flags & APP_TYPE_SERVICE)
- {
set_service_appid_data(chp_final, nullptr, version);
- }
if (http_session->app_type_flags & APP_TYPE_CLIENT)
- {
set_client_app_id_data(chp_final, version);
- }
if (http_session->app_type_flags & APP_TYPE_PAYLOAD)
- {
set_payload_app_id_data((ApplicationId)chp_final, version);
- }
if (http_session->fflow && http_session->fflow->flow_prepared)
{
username_service = serviceAppId;
set_session_flags(APPID_SESSION_LOGIN_SUCCEEDED);
}
+
for (i = 0; i < NUMBER_OF_PTYPES; i++)
{
if (nullptr != chp_rewritten[i])
if (http_session->new_field[i])
snort_free(http_session->new_field[i]);
http_session->new_field[i] = chp_rewritten[i];
+ http_session->new_field_contents = true;
chp_rewritten[i] = nullptr;
}
}
}
int AppIdSession::processHTTPPacket(int direction)
+
{
Profile http_profile_context(httpPerfStats);
constexpr auto RESPONSE_CODE_LENGTH = 3;
char* useragent;
char* referer;
char* via;
- AppInfoTableEntry* entry;
http_session = hsession;
if (!http_session)
if (http_session->response_code)
{
set_session_flags(APPID_SESSION_RESPONSE_CODE_CHECKED);
- if (strlen(http_session->response_code) != RESPONSE_CODE_LENGTH)
- {
- /* received bad response code. Stop processing this asd */
+ if (http_session->response_code_buflen != RESPONSE_CODE_LENGTH) {
+ /* received bad response code. Stop processing this session */
clear_app_id_data();
if (session_logging_enabled)
LogMessage("AppIdDbg %s bad http response code\n", session_logging_id);
}
if (local_subtype)
{
- for (tmpSubtype = &subtype; *tmpSubtype; tmpSubtype =
- &(*tmpSubtype)->next)
+ for (tmpSubtype = &subtype; *tmpSubtype; tmpSubtype = &(*tmpSubtype)->next)
;
*tmpSubtype = local_subtype;
}
// Scan User-Agent for Browser types or Skype
- if ((scan_flags & SCAN_HTTP_USER_AGENT_FLAG) && client_app_id <= APP_ID_NONE
- && useragent && (size = strlen(useragent)) > 0)
+ if ((scan_flags & SCAN_HTTP_USER_AGENT_FLAG) && client_app_id <= APP_ID_NONE
+ && useragent && http_session->useragent_buflen)
{
if (version)
{
snort_free(version);
version = nullptr;
}
- identify_user_agent((uint8_t*)useragent, size, &service_id, &client_id, &version);
+ identify_user_agent((uint8_t*)useragent, http_session->useragent_buflen,
+ &service_id, &client_id, &version);
if (session_logging_enabled && service_id > APP_ID_NONE &&
service_id != APP_ID_HTTP && serviceAppId != service_id)
LogMessage("AppIdDbg %s User Agent is service %d\n", session_logging_id,
if (client_app_id == APP_ID_APPLE_CORE_MEDIA)
{
+ AppInfoTableEntry* entry;
+
if (tp_payload_app_id > APP_ID_NONE)
{
entry = app_info_mgr->get_app_info_entry(tp_payload_app_id);
// only move tpPayloadAppId to client if its got a clientAppId
- if (entry->clientId > APP_ID_NONE)
+ if (entry && entry->clientId > APP_ID_NONE)
{
misc_app_id = client_app_id;
client_app_id = tp_payload_app_id;
{
entry = app_info_mgr->get_app_info_entry(payload_app_id);
// only move payloadAppId to client if it has a ClientAppid
- if (entry->clientId > APP_ID_NONE)
+ if (entry && entry->clientId > APP_ID_NONE)
{
misc_app_id = client_app_id;
client_app_id = payload_app_id;
struct httpSession
{
char* host;
+ uint16_t host_buflen;
char* url;
char* uri;
+ uint16_t uri_buflen;
char* via;
char* useragent;
+ uint16_t useragent_buflen;
char* response_code;
+ uint16_t response_code_buflen;
char* referer;
+ uint16_t referer_buflen;
char* cookie;
+ uint16_t cookie_buflen;
char* content_type;
+ uint16_t content_type_buflen;
char* location;
+ uint16_t location_buflen;
char* body;
+ uint16_t body_buflen;
char* req_body;
+ uint16_t req_body_buflen;
char* server;
char* x_working_with;
char* new_field[HTTP_FIELD_MAX+1];
-
- uint16_t uriOffset;
- uint16_t uriEndOffset;
- uint16_t cookieOffset;
- uint16_t cookieEndOffset;
-
+ uint16_t new_field_len[HTTP_FIELD_MAX+1];
+ uint16_t fieldOffset[HTTP_FIELD_MAX+1];
+ uint16_t fieldEndOffset[HTTP_FIELD_MAX+1];
fflow_info* fflow;
-
+ bool new_field_contents;
int chp_finished;
AppId chp_candidate;
AppId chp_alt_candidate;
int num_matches;
int num_scans;
int get_offsets_from_rebuilt;
- bool skip_simple_detect; // Flag to indicate if simple detection of client ID, payload ID,
- // etc
- // should be skipped
+ bool skip_simple_detect;
sfip_t* xffAddr;
const char** xffPrecedence;
int numXffFields;
int tls_orgUnit_strlen;
};
-/* The UNSYNCED_SNORT_ID value is to cheaply insure we get
- the value from snort rather than assume */
-#define UNSYNCED_SNORT_ID 0x5555
-
void map_app_names_to_snort_ids();
class AppIdSession : public FlowData
{
public:
- AppIdSession(IpProtocol, const sfip_t*);
+ AppIdSession(IpProtocol, const sfip_t*, uint16_t port);
~AppIdSession();
static AppIdSession* allocate_session(const Packet*, IpProtocol, int);
AppIdConfig* config = nullptr;
CommonAppIdData common;
- AppIdSession* next = nullptr;
+ //AppIdSession* next = nullptr;
Flow* flow = nullptr;
AppIdFlowData* flowData = nullptr;
AppInfoManager* app_info_mgr = nullptr;
void* tpsession = nullptr;
uint16_t init_tpPackets = 0;
uint16_t resp_tpPackets = 0;
- uint8_t tp_reinspect_by_initiator = 0;
+ bool tp_reinspect_by_initiator = false;
char* payload_version = nullptr;
uint16_t session_packet_count = 0;
- int16_t snort_id = UNSYNCED_SNORT_ID;
+ int16_t snort_id = 0;
/* Length-based detectors. */
LengthKey length_sequence;
AppId fw_pick_payload_app_id();
AppId fw_pick_referred_payload_app_id();
bool is_ssl_session_decrypted();
+ int processHTTPPacket(Packet*, int, HttpParsedHeaders* const);
+
private:
bool do_client_discovery(int, Packet*);
bool do_service_discovery(IpProtocol, int, AppId, AppId, Packet*);
void stop_rna_service_inspection(Packet*, int);
void set_session_logging_state(const Packet* pkt, int direction);
void clear_app_id_data();
- int initial_CHP_sweep(char**, MatchedCHPAction**);
+ int initial_CHP_sweep(char**, uint16_t*, MatchedCHPAction**);
void clearMiscHttpFlags();
void processCHP(char**, Packet*);
void checkTerminateTpModule(uint16_t tpPktCount);
bool do_third_party_discovery(IpProtocol, const sfip_t*, Packet*, int&);
void pickHttpXffAddress(Packet*, ThirdPartyAppIDAttributeData*);
-
#endif
void create_session_logging_id(int direction, Packet* pkt);
APP_ID_ICAP = 216,
APP_ID_ICA = 217,
APP_ID_ICESHARE = 218,
- APP_ID_ICMP = 219,
- APP_ID_ICMPV6 = 220,
APP_ID_ICP = 221,
APP_ID_ICQ2GO = 222,
APP_ID_IDP = 223,
APP_ID_AOL = 1419,
APP_ID_MDNS = 1755,
APP_ID_APPLE_CORE_MEDIA = 2253,
+ APP_ID_HTTP_TUNNEL = 2296,
APP_ID_ULTRASURF = 2634,
APP_ID_LYCOS = 2775,
APP_ID_DOGPILE = 2804,
APP_ID_ANYCONNECT = 2921,
APP_ID_ANYCONNECT_SSL_CLIENT = 2922,
APP_ID_ANYCONNECT_IPSEC_CLIENT = 2923,
+ APP_ID_ICMP = 3501,
+ APP_ID_ICMPV6 = 3558,
+ APP_ID_HTTP_SSL_TUNNEL = 3860,
APP_ID_FTP_ACTIVE = 4002,
APP_ID_FTP_PASSIVE = 4003,
APP_ID_UNKNOWN_UI = 65535 // this causes the UI to render Unknown instead of pending or blank
#define MAX_VERSION_SIZE 64
-static CLIENT_APP_RETCODE aim_init(const IniClientAppAPI* const, SF_LIST* config);
+static CLIENT_APP_RETCODE aim_init(const InitClientAppAPI* const, SF_LIST* config);
static CLIENT_APP_RETCODE aim_validate( const uint8_t* data, uint16_t size, const int dir,
AppIdSession*, Packet*, Detector*);
{ APP_ID_AOL_INSTANT_MESSENGER, APPINFO_FLAG_CLIENT_ADDITIONAL | APPINFO_FLAG_CLIENT_USER },
};
-static CLIENT_APP_RETCODE aim_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE aim_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
aim_config.enabled = 1;
using RNAClientAppFCN = CLIENT_APP_RETCODE(*)( const uint8_t* data, uint16_t size, const int dir,
AppIdSession*, Packet*, Detector*);
-struct IniClientAppAPI
+struct InitClientAppAPI
{
void (* RegisterPattern)(RNAClientAppFCN, IpProtocol proto, const uint8_t* const pattern,
unsigned size, int position);
void* data = nullptr;
};
-using RNAClientAppInitFCN = CLIENT_APP_RETCODE(*)(const IniClientAppAPI* const, SF_LIST* config);
+using RNAClientAppInitFCN = CLIENT_APP_RETCODE(*)(const InitClientAppAPI* const, SF_LIST* config);
using RNAClientAppFinalizeFCN = CLIENT_APP_RETCODE (*)(const FinalizeClientAppAPI* const);
using RNAClientAppCleanFCN = void(*)();
#include "fw_appid.h"
#include "client_app_api.h"
#include "client_app_base.h"
-#include "client_app_smtp.h"
#include "client_app_msn.h"
#include "client_app_aim.h"
#include "client_app_ym.h"
const uint8_t* const pattern, unsigned size, int position);
static void appSetClientValidator(RNAClientAppFCN fcn, AppId appId, unsigned extractsInfo);
-static IniClientAppAPI client_init_api =
+static InitClientAppAPI client_init_api =
{
&CClientAppRegisterPattern,
&LuaClientAppRegisterPattern,
static RNAClientAppModule* static_client_list[] =
{
- &smtp_client_mod,
&ssh_client_mod,
&msn_client_mod,
&aim_client_mod,
li->module = cam;
cam->api = &client_app_api;
cam->flow_data_index = client_module_index | APPID_SESSION_DATA_CLIENT_MODSTATE_BIT;
+ if (cam->init && cam->init(&client_init_api, nullptr))
+ ErrorMessage("Error initializing client %s\n", cam->name);
+
client_module_index++;
}
/*Can't set cam->userData to nullptr because Lua detectors use it although C detectors don't
break;
}
}
- FreeClientPatternList(&match_list);
- if (sflist_count(asd->candidate_client_list) == 0)
- {
- client = nullptr;
- switch (p->ptrs.dp)
- {
- case 465:
- if (asd->get_session_flags(APPID_SESSION_DECRYPTED))
- client = &smtp_client_mod;
- break;
- default:
- break;
- }
- if (client != nullptr)
- {
- sflist_add_tail(asd->candidate_client_list, (void*)client);
- asd->num_candidate_clients_tried++;
- }
- }
+ FreeClientPatternList(&match_list);
}
int AppIdDiscoverClientApp(Packet* p, int direction, AppIdSession* rnaData)
THREAD_LOCAL BIT_CLIENT_APP_CONFIG bit_config;
-static CLIENT_APP_RETCODE bit_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE bit_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE bit_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_BITTORRENT, 0 }
};
-static CLIENT_APP_RETCODE bit_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE bit_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
RNAClientAppModuleConfigItem* item;
THREAD_LOCAL BIT_CLIENT_APP_CONFIG udp_bit_config;
-static CLIENT_APP_RETCODE udp_bit_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE udp_bit_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE udp_bit_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_BITTRACKER_CLIENT, 0 }
};
-static CLIENT_APP_RETCODE udp_bit_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE udp_bit_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
{ APP_ID_MSNP, APPINFO_FLAG_CLIENT_ADDITIONAL }
};
-static CLIENT_APP_RETCODE msn_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE msn_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
RNAClientAppModuleConfigItem* item;
msn_config.enabled = 1;
THREAD_LOCAL RTP_CLIENT_APP_CONFIG rtp_config;
-static CLIENT_APP_RETCODE rtp_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE rtp_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE rtp_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_RTP, 0 }
};
-static CLIENT_APP_RETCODE rtp_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE rtp_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// client_app_smtp.cc author Sourcefire Inc.
-
-#include "client_app_smtp.h"
-
-#include "main/snort_debug.h"
-#include "protocols/packet.h"
-#include "utils/sflsq.h"
-#include "utils/util.h"
-
-#include "app_info_table.h"
-#include "appid_api.h"
-#include "application_ids.h"
-#include "appid_module.h"
-
-#define UNIT_TESTING 0
-
-#if UNIT_TESTING
-#include "fw_appid.h"
-#endif
-
-enum SMTPState
-{
- SMTP_STATE_NONE,
- SMTP_STATE_HELO,
- SMTP_STATE_MAIL_FROM,
- SMTP_STATE_RCPT_TO,
- SMTP_STATE_DATA,
- SMTP_STATE_MESSAGE,
- SMTP_STATE_GET_PRODUCT_VERSION,
- SMTP_STATE_SKIP_LINE,
- SMTP_STATE_CONNECTION_ERROR,
- SMTP_STATE_STARTTLS
-};
-
-#define MAX_VERSION_SIZE 64
-#define MAX_HEADER_LINE_SIZE 1024
-
-#if UNIT_TESTING
-char* stateName [] =
-{
- "SMTP_STATE_NONE",
- "SMTP_STATE_HELO",
- "SMTP_STATE_MAIL_FROM",
- "SMTP_STATE_RCPT_TO",
- "SMTP_STATE_DATA",
- "SMTP_STATE_MESSAGE",
- "SMTP_STATE_GET_PRODUCT_VERSION",
- "SMTP_STATE_SKIP_LINE",
- "SMTP_STATE_CONNECTION_ERROR",
- "SMTP_STATE_STARTTLS"
-};
-#endif
-
-/* flag values for ClientSMTPData */
-#define CLIENT_FLAG_STARTTLS_SENT 0x01
-#define CLIENT_FLAG_SMTPS 0x02
-
-struct ClientSMTPData
-{
- int flags;
- SMTPState state;
- SMTPState nextstate;
- uint8_t version[MAX_VERSION_SIZE];
- unsigned pos;
- uint8_t* headerline;
-};
-
-struct SMTP_CLIENT_APP_CONFIG
-{
- int enabled;
-};
-
-THREAD_LOCAL SMTP_CLIENT_APP_CONFIG smtp_config;
-
-static CLIENT_APP_RETCODE smtp_init(const IniClientAppAPI* const init_api, SF_LIST* config);
-static CLIENT_APP_RETCODE smtp_validate(const uint8_t* data, uint16_t size, const int dir,
- AppIdSession* asd, Packet* pkt, struct Detector* userData);
-
-SO_PUBLIC RNAClientAppModule smtp_client_mod =
-{
- "SMTP", // name
- IpProtocol::TCP, // proto
- &smtp_init, // init
- nullptr, // clean
- &smtp_validate, // validate
- 1, // minimum_matches
- nullptr, // api
- nullptr, // userData
- 0, // precedence
- nullptr, // finalize,
- 1, // provides_user
- 0 // flow_data_index
-};
-
-struct Client_App_Pattern
-{
- const uint8_t* pattern;
- unsigned length;
- int index;
- unsigned appId;
-};
-
-#define HELO "HELO "
-#define EHLO "EHLO "
-#define MAILFROM "MAIL FROM:"
-#define RCPTTO "RCPT TO:"
-#define DATA "DATA"
-#define RSET "RSET"
-#define AUTH "AUTH PLAIN"
-#define STARTTLS "STARTTLS"
-
-#define STARTTLS_COMMAND_SUCCESS "220 "
-
-#define MICROSOFT "Microsoft "
-#define OUTLOOK "Outlook"
-#define EXPRESS "Express "
-#define IMO "IMO, "
-
-#define XMAILER "X-Mailer: "
-#define USERAGENT "User-Agent: "
-
-static const uint8_t APP_SMTP_OUTLOOK[] = "Microsoft Outlook";
-static const uint8_t APP_SMTP_OUTLOOK_EXPRESS[] = "Microsoft Outlook Express ";
-static const uint8_t APP_SMTP_IMO[] = "IMO, ";
-static const uint8_t APP_SMTP_EVOLUTION[] = "Ximian Evolution ";
-static const uint8_t APP_SMTP_LOTUS_NOTES[] = "Lotus Notes ";
-static const uint8_t APP_SMTP_APPLEMAIL[] = "Apple Mail (";
-static const uint8_t APP_SMTP_EUDORA[] = "QUALCOMM Windows Eudora Version ";
-static const uint8_t APP_SMTP_EUDORAPRO[] = "Windows Eudora Pro Version ";
-static const uint8_t APP_SMTP_AOL[] = "AOL ";
-static const uint8_t APP_SMTP_MUTT[] = "Mutt/";
-static const uint8_t APP_SMTP_KMAIL[] = "KMail/";
-static const uint8_t APP_SMTP_MTHUNDERBIRD[] = "Mozilla Thunderbird ";
-static const uint8_t APP_SMTP_THUNDERBIRD[] = "Thunderbird ";
-static const uint8_t APP_SMTP_MOZILLA[] = "Mozilla";
-static const uint8_t APP_SMTP_THUNDERBIRD_SHORT[] = "Thunderbird/";
-
-static Client_App_Pattern patterns[] =
-{
- { (uint8_t*)HELO, sizeof(HELO)-1, -1, APP_ID_SMTP },
- { (uint8_t*)EHLO, sizeof(EHLO)-1, -1, APP_ID_SMTP },
- { APP_SMTP_OUTLOOK, sizeof(APP_SMTP_OUTLOOK)-1, -1, APP_ID_OUTLOOK },
- { APP_SMTP_OUTLOOK_EXPRESS, sizeof(APP_SMTP_OUTLOOK_EXPRESS)-1,-1, APP_ID_OUTLOOK_EXPRESS },
- { APP_SMTP_IMO, sizeof(APP_SMTP_IMO)-1, -1, APP_ID_SMTP_IMO },
- { APP_SMTP_EVOLUTION, sizeof(APP_SMTP_EVOLUTION)-1, -1, APP_ID_EVOLUTION },
- { APP_SMTP_LOTUS_NOTES, sizeof(APP_SMTP_LOTUS_NOTES)-1, -1, APP_ID_LOTUS_NOTES },
- { APP_SMTP_APPLEMAIL, sizeof(APP_SMTP_APPLEMAIL)-1, -1, APP_ID_APPLE_EMAIL },
- { APP_SMTP_EUDORA, sizeof(APP_SMTP_EUDORA)-1, -1, APP_ID_EUDORA },
- { APP_SMTP_EUDORAPRO, sizeof(APP_SMTP_EUDORAPRO)-1, -1, APP_ID_EUDORA_PRO },
- { APP_SMTP_AOL, sizeof(APP_SMTP_AOL)-1, -1, APP_ID_AOL_EMAIL },
- { APP_SMTP_MUTT, sizeof(APP_SMTP_MUTT)-1, -1, APP_ID_MUTT },
- { APP_SMTP_KMAIL, sizeof(APP_SMTP_KMAIL)-1, -1, APP_ID_KMAIL },
- { APP_SMTP_MTHUNDERBIRD, sizeof(APP_SMTP_MTHUNDERBIRD)-1, -1, APP_ID_THUNDERBIRD },
- { APP_SMTP_THUNDERBIRD, sizeof(APP_SMTP_THUNDERBIRD)-1, -1, APP_ID_THUNDERBIRD },
-};
-
-static AppRegistryEntry appIdRegistry[] =
-{
- { APP_ID_THUNDERBIRD, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_OUTLOOK, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_KMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_EUDORA_PRO, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_EVOLUTION, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_SMTP_IMO, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_EUDORA, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_LOTUS_NOTES, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_APPLE_EMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_AOL_EMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_MUTT, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_SMTP, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_OUTLOOK_EXPRESS, APPINFO_FLAG_CLIENT_ADDITIONAL },
- { APP_ID_SMTPS, APPINFO_FLAG_CLIENT_ADDITIONAL }
-};
-
-static CLIENT_APP_RETCODE smtp_init(const IniClientAppAPI* const init_api, SF_LIST* config)
-{
- unsigned i;
-
- smtp_config.enabled = 1;
-
- if (config)
- {
- SF_LNODE* cursor;
- RNAClientAppModuleConfigItem* item;
-
- for (item = (RNAClientAppModuleConfigItem*)sflist_first(config, &cursor);
- item;
- item = (RNAClientAppModuleConfigItem*)sflist_next(&cursor))
- {
- DebugFormat(DEBUG_LOG,"Processing %s: %s\n",item->name, item->value);
- if (strcasecmp(item->name, "enabled") == 0)
- {
- smtp_config.enabled = atoi(item->value);
- }
- }
- }
-
- if (smtp_config.enabled)
- {
- for (i=0; i < sizeof(patterns)/sizeof(*patterns); i++)
- {
- init_api->RegisterPattern(&smtp_validate, IpProtocol::TCP, patterns[i].pattern,
- patterns[i].length, patterns[i].index);
- }
- }
-
- unsigned j;
- for (j=0; j < sizeof(appIdRegistry)/sizeof(*appIdRegistry); j++)
- {
- DebugFormat(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[j].appId);
- init_api->RegisterAppId(&smtp_validate, appIdRegistry[j].appId,
- appIdRegistry[j].additionalInfo);
- }
-
- return CLIENT_APP_SUCCESS;
-}
-
-/*
- * product - The product data should not include any characters
- * after the end of the product version (e.g. no CR, LF, etc).
- * prefix_len - The number of characters that are the prefix to the version,
- * including the NUL terminating character.
- */
-static int extract_version_and_add_client_app(ApplicationId clientId, const int prefix_len,
- const uint8_t* product, const uint8_t* product_end, ClientSMTPData* const client_data,
- AppIdSession* asd, AppId appId, PegCount *stat_counter)
-{
- const uint8_t* p;
- uint8_t* v;
- uint8_t* v_end;
-
- v_end = client_data->version;
- v_end += MAX_VERSION_SIZE - 1;
-
- // The prefix_len includes the NUL character, but product does not, so
- // subtract 1 from length to skip.
- p = product + prefix_len - 1;
- if (p >= product_end || isspace(*p))
- return 1;
- for (v=client_data->version; v<v_end && p < product_end; v++,p++)
- {
- *v = *p;
- }
- *v = 0;
- smtp_client_mod.api->add_app(asd, appId, clientId, (char*)client_data->version);
- (*stat_counter)++;
- return 0;
-}
-
-
-/*
- * Identify the product and version of the SMTP client.
- *
- * Returns 0 if a recognized product is found. Otherwise returns 1.
- */
-static int IdentifyClientVersion(ClientSMTPData* const fd, const uint8_t* product,
- const uint8_t* data_end, AppIdSession* asd, Packet*)
-{
- const uint8_t* p;
- uint8_t* v;
- uint8_t* v_end;
- unsigned len;
- unsigned sublen;
- AppId appId = (fd->flags & CLIENT_FLAG_SMTPS) ? APP_ID_SMTPS : APP_ID_SMTP;
-
- v_end = fd->version;
- v_end += MAX_VERSION_SIZE - 1;
- len = data_end - product;
- if (len >= sizeof(MICROSOFT) && memcmp(product, MICROSOFT, sizeof(MICROSOFT)-1) == 0)
- {
- p = product + sizeof(MICROSOFT) - 1;
-
- if (data_end-p >= (int)sizeof(OUTLOOK) && memcmp(p, OUTLOOK, sizeof(OUTLOOK)-1) == 0)
- {
- p += sizeof(OUTLOOK) - 1;
- if (p >= data_end)
- return 1;
- if (*p == ',')
- {
- p++;
- if (p >= data_end || *p != ' ')
- return 1;
- return extract_version_and_add_client_app(APP_ID_OUTLOOK,
- 2, p, data_end, fd, asd, appId,
- &appid_stats.smtp_microsoft_outlook_clients);
- }
- else if (*p == ' ')
- {
- 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,
- &appid_stats.smtp_microsoft_outlook_express_clients);
- }
- 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,
- &appid_stats.smtp_microsoft_outlook_imo_clients);
- }
- }
- }
- }
- else if (len >= sizeof(APP_SMTP_EVOLUTION) && memcmp(product, APP_SMTP_EVOLUTION,
- 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,
- &appid_stats.smtp_evolution_clients);
- }
- 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,
- &appid_stats.smtp_lotus_notes_clients);
- }
- else if (len >= sizeof(APP_SMTP_APPLEMAIL) && memcmp(product, APP_SMTP_APPLEMAIL,
- sizeof(APP_SMTP_APPLEMAIL)-1) == 0)
- {
- p = product + sizeof(APP_SMTP_APPLEMAIL) - 1;
- if (p >= data_end || *(data_end - 1) != ')' || *p == ')' || isspace(*p))
- return 1;
- for (v=fd->version; v<v_end && p < data_end-1; v++,p++)
- {
- *v = *p;
- }
- *v = 0;
- smtp_client_mod.api->add_app(asd, appId, APP_ID_APPLE_EMAIL, (char*)fd->version);
- appid_stats.smtp_applemail_clients++;
- 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,
- &appid_stats.smtp_eudora_clients);
- }
- 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,
- &appid_stats.smtp_eudora_pro_clients);
- }
- 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,
- &appid_stats.smtp_aol_clients);
- }
- 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,
- &appid_stats.smtp_mutt_clients);
- }
- 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,
- &appid_stats.smtp_kmail_clients);
- }
- 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,
- &appid_stats.smtp_thunderbird_clients);
- }
- 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,
- &appid_stats.smtp_thunderbird_clients);
- }
- else if (len >= sizeof(APP_SMTP_MOZILLA) && memcmp(product, APP_SMTP_MOZILLA,
- sizeof(APP_SMTP_MOZILLA)-1) == 0)
- {
- for (p = product + sizeof(APP_SMTP_MOZILLA) - 1; p < data_end; p++)
- {
- if (*p == 'T')
- {
- sublen = data_end - p;
- if (sublen >= sizeof(APP_SMTP_THUNDERBIRD_SHORT) && memcmp(p,
- APP_SMTP_THUNDERBIRD_SHORT, sizeof(APP_SMTP_THUNDERBIRD_SHORT)-1) == 0)
- {
- return extract_version_and_add_client_app(
- APP_ID_THUNDERBIRD, sizeof(APP_SMTP_THUNDERBIRD_SHORT),
- p, data_end, fd, asd, appId,
- &appid_stats.smtp_thunderbird_clients);
- }
- }
- }
- }
-
- return 1;
-}
-
-static void freeData(void* data)
-{
- ClientSMTPData* fd = (ClientSMTPData*)data;
- snort_free(fd->headerline);
- snort_free(fd);
-}
-
-static CLIENT_APP_RETCODE smtp_validate(const uint8_t* data, uint16_t size, const int dir,
- AppIdSession* asd, Packet* pkt, struct Detector*)
-{
- ClientSMTPData* fd;
- const uint8_t* end;
-#if UNIT_TESTING
- SMTPState currState = SMTP_STATE_NONE;
-#endif
-
- fd = (ClientSMTPData*)smtp_client_mod.api->data_get(asd, smtp_client_mod.flow_data_index);
- if (!fd)
- {
- fd = (ClientSMTPData*)snort_calloc(sizeof(ClientSMTPData));
- if (!fd)
- return CLIENT_APP_ENOMEM;
- if (smtp_client_mod.api->data_add(asd, fd, smtp_client_mod.flow_data_index, &freeData))
- {
- snort_free(fd);
- return CLIENT_APP_ENOMEM;
- }
- fd->state = SMTP_STATE_HELO;
- }
-
- if (dir != APP_ID_FROM_INITIATOR)
- {
- if ( (fd->flags & CLIENT_FLAG_STARTTLS_SENT) &&
- !memcmp(data,STARTTLS_COMMAND_SUCCESS,sizeof(STARTTLS_COMMAND_SUCCESS)-1) )
- {
- fd->flags &= ~(CLIENT_FLAG_STARTTLS_SENT);
- fd->flags |= CLIENT_FLAG_SMTPS;
- asd->clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS); // we no longer need
- // to examine the
- // response.
- if (!asd->get_session_flags(APPID_SESSION_DECRYPTED))
- {
- /* 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
- IdentifyClientVersion() worthwhile, So set the appid and call it good. */
- smtp_client_mod.api->add_app(asd, APP_ID_SMTPS, APP_ID_SMTPS, nullptr);
- goto done;
- }
- }
- return CLIENT_APP_INPROCESS;
- }
- if (asd->get_session_flags(APPID_SESSION_ENCRYPTED))
- {
- if (!asd->get_session_flags(APPID_SESSION_DECRYPTED))
- return CLIENT_APP_INPROCESS;
- }
-
- for (end = data + size; data < end; data++)
- {
-#if UNIT_TESTING
- if (session_logging_enabled && currState != fd->state)
- {
- DEBUG_WRAP(DebugMessage(DEBUG_APPID, "AppIdDbg %s SMTP client state %s\n",
- session_logging_id, stateName[fd->state]); );
- currState = fd->state;
- }
-#endif
- switch (fd->state)
- {
- case SMTP_STATE_HELO:
- if (*data == HELO[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(HELO))
- {
- fd->pos = 0;
- fd->nextstate = SMTP_STATE_MAIL_FROM;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else if (*data == EHLO[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(EHLO))
- {
- fd->pos = 0;
- fd->nextstate = SMTP_STATE_MAIL_FROM;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else
- goto done;
- break;
-
- case SMTP_STATE_MAIL_FROM:
- if (*data == MAILFROM[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(MAILFROM))
- {
- fd->pos = 0;
- fd->nextstate = SMTP_STATE_RCPT_TO;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else if (*data == RSET[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(RSET))
- {
- fd->pos = 0;
- fd->nextstate = fd->state;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else if (*data == AUTH[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(AUTH))
- {
- fd->pos = 0;
- fd->nextstate = fd->state;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else if (*data == STARTTLS[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(STARTTLS))
- {
- fd->flags |= CLIENT_FLAG_STARTTLS_SENT;
- fd->pos = 0;
- fd->nextstate = fd->state;
- fd->state = SMTP_STATE_SKIP_LINE;
- asd->set_session_flags(APPID_SESSION_ENCRYPTED);
- }
- }
- else
- goto done;
- break;
-
- case SMTP_STATE_RCPT_TO:
- if (*data == RCPTTO[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(RCPTTO))
- {
- fd->pos = 0;
- fd->nextstate = SMTP_STATE_DATA;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else
- goto done;
- break;
-
- case SMTP_STATE_DATA:
- if (*data == DATA[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(DATA))
- {
- fd->pos = 0;
- fd->nextstate = SMTP_STATE_MESSAGE;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- else if (*data == RCPTTO[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(RCPTTO))
- {
- fd->pos = 0;
- fd->nextstate = fd->state;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- }
- break;
-
- case SMTP_STATE_MESSAGE:
- if (*data == '.')
- {
- unsigned len = end - data;
- if (len == 0 ||
- (len >= 1 && data[1] == 0x0A) ||
- (len >= 2 && data[1] == 0x0D && data[2] == 0x0A))
- {
- AppId appId = (fd->flags & CLIENT_FLAG_SMTPS) ? APP_ID_SMTPS : APP_ID_SMTP;
- smtp_client_mod.api->add_app(asd, appId, appId, nullptr);
- goto done;
- }
- }
- else if (*data == XMAILER[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(XMAILER))
- {
- fd->pos = 0;
- fd->state = SMTP_STATE_GET_PRODUCT_VERSION;
- }
- }
- else if (*data == USERAGENT[fd->pos])
- {
- fd->pos++;
- if (fd->pos == strlen(USERAGENT))
- {
- fd->pos = 0;
- fd->state = SMTP_STATE_GET_PRODUCT_VERSION;
- }
- }
- else if (!isprint(*data) && *data != 0x09)
- goto done;
- else
- {
- fd->pos = 0;
- fd->nextstate = fd->state;
- fd->state = SMTP_STATE_SKIP_LINE;
- }
- break;
-
- case SMTP_STATE_GET_PRODUCT_VERSION:
- if (*data == 0x0D)
- {
- if (fd->headerline && fd->pos)
- {
- IdentifyClientVersion(fd, fd->headerline, fd->headerline + fd->pos, asd, pkt);
- snort_free(fd->headerline);
- fd->headerline = nullptr;
- }
- goto done;
- }
- else if (!isprint(*data))
- {
- snort_free(fd->headerline);
- fd->headerline = nullptr;
- goto done;
- }
- else
- {
- if (!fd->headerline)
- {
- if (!(fd->headerline = (uint8_t*)snort_calloc(MAX_HEADER_LINE_SIZE)))
- goto done;
- }
-
- if (fd->pos < (MAX_HEADER_LINE_SIZE-1))
- fd->headerline[fd->pos++] = *data;
- }
- break;
-
- case SMTP_STATE_SKIP_LINE:
- if (*data == 0x0A)
- {
- fd->pos = 0;
- fd->state = fd->nextstate;
- fd->nextstate = SMTP_STATE_NONE;
- }
- else if (!(*data == 0x0D || isprint(*data)))
- goto done;
- break;
-
- default:
- goto done;
- }
- }
- return CLIENT_APP_INPROCESS;
-
-done:
- asd->set_session_flags(APPID_SESSION_CLIENT_DETECTED);
- return CLIENT_APP_SUCCESS;
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// client_app_smtp.h author Sourcefire Inc.
-
-#ifndef CLIENT_APP_SMTP_H
-#define CLIENT_APP_SMTP_H
-
-#include "client_app_api.h"
-
-extern RNAClientAppModule smtp_client_mod;
-
-#endif
-
THREAD_LOCAL SSH_CLIENT_CONFIG ssh_client_config;
-static CLIENT_APP_RETCODE ssh_client_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE ssh_client_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE ssh_client_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_OPENSSH, APPINFO_FLAG_CLIENT_ADDITIONAL }
};
-static CLIENT_APP_RETCODE ssh_client_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE ssh_client_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
THREAD_LOCAL TIMBUKTU_CLIENT_APP_CONFIG timbuktu_config;
-static CLIENT_APP_RETCODE timbuktu_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE timbuktu_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE timbuktu_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_TIMBUKTU, 0 }
};
-static CLIENT_APP_RETCODE timbuktu_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE timbuktu_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
#endif
THREAD_LOCAL TNS_CLIENT_APP_CONFIG tns_config;
-static CLIENT_APP_RETCODE tns_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE tns_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE tns_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_ORACLE_DATABASE, APPINFO_FLAG_CLIENT_ADDITIONAL | APPINFO_FLAG_CLIENT_USER }
};
-static CLIENT_APP_RETCODE tns_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE tns_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
THREAD_LOCAL VNC_CLIENT_APP_CONFIG vnc_config;
-static CLIENT_APP_RETCODE vnc_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE vnc_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE vnc_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_VNC_RFB, APPINFO_FLAG_CLIENT_ADDITIONAL }
};
-static CLIENT_APP_RETCODE vnc_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE vnc_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
#define MAX_VERSION_SIZE 64
-static CLIENT_APP_RETCODE ym_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE ym_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE ym_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ APP_ID_YAHOO_MSG, APPINFO_FLAG_CLIENT_ADDITIONAL }
};
-static CLIENT_APP_RETCODE ym_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE ym_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
+++ /dev/null
-
-AM_DEFAULT_SOURCE_EXT = .cc
-
-check_PROGRAMS = \
-client_app_smtp_test
-
-TESTS = $(check_PROGRAMS)
-
-client_app_smtp_test_CPPFLAGS = -I$(top_srcdir)/src/network_inspectors/appid @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
-
-client_app_smtp_test_LDADD = \
-../../appid_stats_counter.o \
-../../../../utils/libutils.a \
-@CPPUTEST_LDFLAGS@
-
#include "detector_api.h"
#include "log/messages.h"
#include "service_plugins/service_base.h"
+#include "detector_plugins/detector_smtp.h"
static void* detector_flowdata_get(AppIdSession* asd, unsigned detector_id);
static int detector_flowdata_add(AppIdSession* asd, void* data, unsigned detector_id,
{
&imap_detector_mod,
&pop3_detector_mod,
+ &smtp_detector_mod,
&kerberos_detector_mod
};
const uint32_t NUM_STATIC_DETECTORS =
MatchedDNSPatterns* next;
};
-static int dns_service_init(const IniServiceAPI* const);
+static int dns_service_init(const InitServiceAPI* const);
static int dns_udp_validate(ServiceValidationArgs*);
static int dns_tcp_validate(ServiceValidationArgs*);
{ APP_ID_DNS, APPINFO_FLAG_SERVICE_UDP_REVERSED | APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static CLIENT_APP_RETCODE dns_udp_client_init(const IniClientAppAPI* const, SF_LIST*);
-static CLIENT_APP_RETCODE dns_tcp_client_init(const IniClientAppAPI* const, SF_LIST*);
+static CLIENT_APP_RETCODE dns_udp_client_init(const InitClientAppAPI* const, SF_LIST*);
+static CLIENT_APP_RETCODE dns_tcp_client_init(const InitClientAppAPI* const, SF_LIST*);
static CLIENT_APP_RETCODE dns_udp_client_validate(const uint8_t*, uint16_t, const int,
AppIdSession*, Packet*, Detector*);
static CLIENT_APP_RETCODE dns_tcp_client_validate(const uint8_t*, uint16_t, const int,
};
static THREAD_LOCAL ServiceDnsConfig serviceDnsConfig; // DNS service configuration
-static CLIENT_APP_RETCODE dns_udp_client_init(const IniClientAppAPI* const, SF_LIST*)
+static CLIENT_APP_RETCODE dns_udp_client_init(const InitClientAppAPI* const, SF_LIST*)
{
return CLIENT_APP_SUCCESS;
}
-static CLIENT_APP_RETCODE dns_tcp_client_init(const IniClientAppAPI* const, SF_LIST*)
+static CLIENT_APP_RETCODE dns_tcp_client_init(const InitClientAppAPI* const, SF_LIST*)
{
return CLIENT_APP_SUCCESS;
}
return retVal;
}
-static int dns_service_init(const IniServiceAPI* const init_api)
+static int dns_service_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
tMlmpTree* RTMPHosUrlMatcher = nullptr;
SearchTool* header_matcher = nullptr;
SearchTool* content_type_matcher = nullptr;
+ SearchTool* field_matcher = nullptr;
SearchTool* chp_matchers[MAX_PATTERN_TYPE + 1] = { nullptr };
HosUrlPatternsList* hosUrlPatternsList = nullptr;
};
}
}
+void remove_http_patterns_for_id( AppId id )
+{
+ // Walk the list of all the patterns we have inserted, searching for this appIdInstance and free them.
+ // The purpose is for the 14 and 15 to be used together to only set the APPINFO_FLAG_SEARCH_ENGINE flag
+ // If the reserved pattern is not used, it is a mixed use case and should just behave normally.
+ CHPListElement* chpa = nullptr;
+ CHPListElement* prev_chpa = nullptr;
+ CHPListElement* tmp_chpa = httpPatternLists->chpList;
+ while (tmp_chpa)
+ {
+ if (tmp_chpa->chp_action.appIdInstance == id)
+ {
+ // advance the tmp_chpa pointer by removing the item pointed to. Keep prev_chpa unchanged.
+
+ // 1) unlink the struct, 2) free strings and then 3) free the struct.
+ chpa = tmp_chpa; // preserve this pointer to be freed at the end.
+ if (prev_chpa == NULL)
+ {
+ // Remove from head
+ httpPatternLists->chpList = tmp_chpa->next;
+ tmp_chpa = httpPatternLists->chpList;
+ }
+ else
+ {
+ // Remove from middle of list.
+ prev_chpa->next = tmp_chpa->next;
+ tmp_chpa = prev_chpa->next;
+ }
+ snort_free(chpa->chp_action.pattern);
+ if (chpa->chp_action.action_data)
+ snort_free(chpa->chp_action.action_data);
+ snort_free(chpa);
+ }
+ else
+ {
+ // advance both pointers
+ prev_chpa = tmp_chpa;
+ tmp_chpa = tmp_chpa->next;
+ }
+ }
+}
+
void insert_content_type_pattern(HTTPListElement* element)
{
element->next = httpPatternLists->contentTypePatternList;
MatchedPatterns** matches = (MatchedPatterns**)data;
DetectorHTTPPattern* target = (DetectorHTTPPattern*)id;
- /* make sure we haven't already seen this pattern */
+ // make sure we haven't already seen this pattern
for (tmp = matches; *tmp; tmp = &(*tmp)->next)
cm = *tmp;
for (uint32_t i = 0; i < patternListCount; i++)
{
- patternMatcher->add(patternList[i].pattern,
- patternList[i].pattern_size,
- &patternList[i],
- false);
+ patternMatcher->add(patternList[i].pattern, patternList[i].pattern_size,
+ &patternList[i], false);
}
- /* Add patterns from Lua API */
+ // Add patterns from Lua API
for (element = luaPatternList; element; element = element->next)
{
patternMatcher->add(element->detectorHTTPPattern.pattern,
element->detectorHTTPPattern.pattern_size,
- &element->detectorHTTPPattern,
- false);
+ &element->detectorHTTPPattern, false);
}
patternMatcher->prep();
return patternMatcher;
}
+#define HTTP_FIELD_PREFIX_USER_AGENT "\r\nUser-Agent: "
+#define HTTP_FIELD_PREFIX_USER_AGENT_SIZE (sizeof(HTTP_FIELD_PREFIX_USER_AGENT)-1)
+#define HTTP_FIELD_PREFIX_HOST "\r\nHost: "
+#define HTTP_FIELD_PREFIX_HOST_SIZE (sizeof(HTTP_FIELD_PREFIX_HOST)-1)
+#define HTTP_FIELD_PREFIX_REFERER "\r\nReferer: "
+#define HTTP_FIELD_PREFIX_REFERER_SIZE (sizeof(HTTP_FIELD_PREFIX_REFERER)-1)
+#define HTTP_FIELD_PREFIX_URI " "
+#define HTTP_FIELD_PREFIX_URI_SIZE (sizeof(HTTP_FIELD_PREFIX_URI)-1)
+#define HTTP_FIELD_PREFIX_COOKIE "\r\nCookie: "
+#define HTTP_FIELD_PREFIX_COOKIE_SIZE (sizeof(HTTP_FIELD_PREFIX_COOKIE)-1)
+
+typedef struct _FIELD_PATTERN
+{
+ PatternType patternType;
+ uint8_t* data;
+ unsigned length;
+} FieldPattern;
+
+static FieldPattern http_field_patterns[] =
+{
+ {URI_PT, (uint8_t*) HTTP_FIELD_PREFIX_URI, HTTP_FIELD_PREFIX_URI_SIZE},
+ {HOST_PT, (uint8_t*) HTTP_FIELD_PREFIX_HOST,HTTP_FIELD_PREFIX_HOST_SIZE},
+ {REFERER_PT, (uint8_t*) HTTP_FIELD_PREFIX_REFERER, HTTP_FIELD_PREFIX_REFERER_SIZE},
+ {COOKIE_PT, (uint8_t*) HTTP_FIELD_PREFIX_COOKIE, HTTP_FIELD_PREFIX_COOKIE_SIZE},
+ {AGENT_PT, (uint8_t*) HTTP_FIELD_PREFIX_USER_AGENT,HTTP_FIELD_PREFIX_USER_AGENT_SIZE},
+};
+
+static SearchTool* processHttpFieldPatterns(FieldPattern* patternList, size_t patternListCount)
+{
+ u_int32_t i;
+
+ SearchTool* patternMatcher = new SearchTool("ac_full");
+
+ for (i=0; i < patternListCount; i++)
+ patternMatcher->add( (char *)patternList[i].data, patternList[i].length,
+ &patternList[i], false);
+
+ patternMatcher->prep();
+ return patternMatcher;
+}
+
+typedef struct fieldPatternData_t
+{
+ const uint8_t*payload;
+ unsigned length;
+ httpSession *hsession;
+} FieldPatternData;
+
+static int http_field_pattern_match(void *id, void *, int index, void *data, void *)
+{
+ static const uint8_t crlf[] = "\r\n";
+ static unsigned crlfLen = sizeof(crlf)-1;
+ FieldPatternData *pFieldData = (FieldPatternData*)data;
+ FieldPattern *target = (FieldPattern *)id;
+ const uint8_t* p;
+ unsigned fieldOffset = target->length + index;
+ unsigned remainingLength = pFieldData->length - fieldOffset;
+
+ if (!(p = (uint8_t*)service_strstr(&pFieldData->payload[fieldOffset], remainingLength, crlf, crlfLen)))
+ {
+ return 1;
+ }
+ pFieldData->hsession->fieldOffset[target->patternType] = (uint16_t)fieldOffset;
+ pFieldData->hsession->fieldEndOffset[target->patternType] = p - pFieldData->payload;
+ return 1;
+}
+
+void httpGetNewOffsetsFromPacket(Packet *pkt, httpSession *hsession)
+{
+ constexpr auto MIN_HTTP_REQ_HEADER_SIZE = (sizeof("GET /\r\n\r\n") - 1);
+ static const uint8_t crlfcrlf[] = "\r\n\r\n";
+ static unsigned crlfcrlfLen = sizeof(crlfcrlf) - 1;
+ uint8_t*headerEnd;
+ unsigned fieldId;
+ FieldPatternData patternMatchData;
+
+ for (fieldId = AGENT_PT; fieldId <= COOKIE_PT; fieldId++)
+ hsession->fieldOffset[fieldId] = 0;
+
+
+ if (!pkt->data || pkt->dsize < MIN_HTTP_REQ_HEADER_SIZE)
+ return;
+
+ patternMatchData.hsession = hsession;
+ patternMatchData.payload = pkt->data;
+
+ if (!(headerEnd = (uint8_t*)service_strstr(pkt->data, pkt->dsize, crlfcrlf, crlfcrlfLen)))
+ return;
+
+ headerEnd += crlfcrlfLen;
+ patternMatchData.length = (unsigned)(headerEnd - pkt->data);
+ detectorHttpConfig->field_matcher->find_all((char*)pkt->data, patternMatchData.length,
+ &http_field_pattern_match, false, (void*)(&patternMatchData));
+
+}
+
int finalize_http_detector()
{
size_t upc = 0;
if (!detectorHttpConfig->content_type_matcher)
return -1;
+ numPatterns = sizeof(http_field_patterns)/sizeof(*http_field_patterns);
+ detectorHttpConfig->field_matcher = processHttpFieldPatterns(http_field_patterns, numPatterns);
+ if (!detectorHttpConfig->field_matcher)
+ return -1;
+
if (!processCHPList(httpPatternLists->chpList))
return -1;
delete detectorHttpConfig->client_agent_matcher;
delete detectorHttpConfig->header_matcher;
delete detectorHttpConfig->content_type_matcher;
+ delete detectorHttpConfig->field_matcher;
for (size_t i = 0; i <= MAX_PATTERN_TYPE; i++)
delete detectorHttpConfig->chp_matchers[i];
int i, old_size;
int percent_count = 0;
char a, b;
- char* tmp_ret, * tmp_user;
+ char* tmp_ret, *tmp_user;
old_size = strlen(user);
// knowledge" case for HTTP/2 (i.e., the client knows the server supports
// HTTP/2 and jumps right in with the preface).
-static CLIENT_APP_RETCODE http_client_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE http_client_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE http_client_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
-static int http_service_init(const IniServiceAPI* const init_api);
+static int http_service_init(const InitServiceAPI* const init_api);
static int http_service_validate(ServiceValidationArgs* args);
static AppRegistryEntry appIdRegistry[] =
0
};
-static CLIENT_APP_RETCODE http_client_init(const IniClientAppAPI* const init_api, SF_LIST*)
+static CLIENT_APP_RETCODE http_client_init(const InitClientAppAPI* const init_api, SF_LIST*)
{
if (AppIdConfig::get_appid_config()->mod_config->http2_detection_enabled)
{
return CLIENT_APP_SUCCESS;
}
-static int http_service_init(const IniServiceAPI* const init_api)
+static int http_service_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
void clean_http_detector();
void insert_chp_pattern(CHPListElement* chpa);
void insert_http_pattern_element(enum httpPatternType pType, HTTPListElement* element);
+void remove_http_patterns_for_id( AppId id );
void insert_content_type_pattern(HTTPListElement* element);
void insert_url_pattern(DetectorAppUrlPattern* pattern);
void insert_rtmp_url_pattern(DetectorAppUrlPattern* pattern);
void insert_app_url_pattern(DetectorAppUrlPattern* pattern);
int get_appid_by_pattern(const uint8_t*, unsigned, char**);
int get_http_header_location(const uint8_t*, unsigned, HttpId, int*, int*, HeaderMatchedPatterns*);
+void httpGetNewOffsetsFromPacket(Packet *pkt, httpSession *hsession);
+
inline void free_matched_chp_actions(MatchedCHPAction* ma)
{
MatchedCHPAction* tmp;
static CLIENT_APP_CONFIG ca_config;
-static CLIENT_APP_RETCODE init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE init(const InitClientAppAPI* const init_api, SF_LIST* config);
static void clean();
static CLIENT_APP_RETCODE validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, Detector* userData);
#endif
};
-static int imap_init(const IniServiceAPI* const init_api);
+static int imap_init(const InitServiceAPI* const init_api);
static int imap_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_IMAPS, APPINFO_FLAG_CLIENT_USER }
};
-static CLIENT_APP_RETCODE init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
RNAClientAppModuleConfigItem* item;
return CLIENT_APP_SUCCESS;
}
-static int imap_init(const IniServiceAPI* const init_api)
+static int imap_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPatternUser(&imap_validate, IpProtocol::TCP, (uint8_t*)IMAP_PATTERN,
sizeof(IMAP_PATTERN)-1, 0, "imap");
static KRB_CLIENT_APP_CONFIG krb_client_config;
-static CLIENT_APP_RETCODE krb_client_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE krb_client_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE krb_client_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
{ TGS_REQ_4, sizeof(TGS_REQ_4)-1 },
};
-static int krb_server_init(const IniServiceAPI* const init_api);
+static int krb_server_init(const InitServiceAPI* const init_api);
static int krb_server_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_KERBEROS, APPINFO_FLAG_CLIENT_USER | APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static CLIENT_APP_RETCODE krb_client_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE krb_client_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
RNAClientAppModuleConfigItem* item;
return CLIENT_APP_SUCCESS;
}
-static int krb_server_init(const IniServiceAPI* const init_api)
+static int krb_server_init(const InitServiceAPI* const init_api)
{
unsigned i;
static int service_validate(ServiceValidationArgs* args);
static int csdPatternTreeSearch(const uint8_t* data, uint16_t size, IpProtocol protocol, Packet* pkt,
const RNAServiceElement** serviceData, bool isClient);
-static int pattern_service_init(const IniServiceAPI* const iniServiceApi);
+static int pattern_service_init(const InitServiceAPI* const iniServiceApi);
static void pattern_service_clean();
-static CLIENT_APP_RETCODE client_init(const IniClientAppAPI* const init_api, SF_LIST* config);
-static CLIENT_APP_RETCODE client_init_tcp(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE client_init(const InitClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE client_init_tcp(const InitClientAppAPI* const init_api, SF_LIST* config);
static CLIENT_APP_RETCODE client_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
static void client_clean();
-static const IniServiceAPI* iniServiceApi;
-static const IniClientAppAPI* iniClientApi;
+static const InitServiceAPI* iniServiceApi;
+static const InitClientAppAPI* iniClientApi;
static const RNAServiceElement svc_element =
{
}
// Register ports for detectors which have a pattern associated with it.
-static void install_ports(PatternService* serviceList, const IniServiceAPI* const iniServiceApi)
+static void install_ports(PatternService* serviceList, const InitServiceAPI* const iniServiceApi)
{
PatternService* ps;
PortNode* port;
dumpPatterns("Server", service_port_patterns.servicePortPattern);
}
-static int pattern_service_init(const IniServiceAPI* const init_api)
+static int pattern_service_init(const InitServiceAPI* const init_api)
{
iniServiceApi = init_api;
return SERVICE_NOMATCH;
}
-static CLIENT_APP_RETCODE client_init(const IniClientAppAPI* const init_api, SF_LIST*)
+static CLIENT_APP_RETCODE client_init(const InitClientAppAPI* const init_api, SF_LIST*)
{
iniClientApi = init_api;
return CLIENT_APP_SUCCESS;
}
-static CLIENT_APP_RETCODE client_init_tcp(const IniClientAppAPI* const, SF_LIST*)
+static CLIENT_APP_RETCODE client_init_tcp(const InitClientAppAPI* const, SF_LIST*)
{
return CLIENT_APP_SUCCESS;
}
static POP3_CLIENT_APP_CONFIG pop3_config;
-static CLIENT_APP_RETCODE pop3_ca_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE pop3_ca_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static void pop3_ca_clean();
static CLIENT_APP_RETCODE pop3_ca_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, struct Detector* userData);
int error;
};
-static int pop3_init(const IniServiceAPI* const init_api);
+static int pop3_init(const InitServiceAPI* const init_api);
static int pop3_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_POP3S, APPINFO_FLAG_SERVICE_ADDITIONAL | APPINFO_FLAG_CLIENT_USER }
};
-static CLIENT_APP_RETCODE pop3_ca_init(const IniClientAppAPI* const init_api, SF_LIST* config)
+static CLIENT_APP_RETCODE pop3_ca_init(const InitClientAppAPI* const init_api, SF_LIST* config)
{
unsigned i;
RNAClientAppModuleConfigItem* item;
return CLIENT_APP_SUCCESS;
}
-static int pop3_init(const IniServiceAPI* const init_api)
+static int pop3_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPatternUser(&pop3_validate, IpProtocol::TCP, (uint8_t*)POP3_OK,
sizeof(POP3_OK)-1, 0, "pop3");
static THREAD_LOCAL DetectorSipConfig detector_sip_config;
-static CLIENT_APP_RETCODE sip_client_init(const IniClientAppAPI* const init_api, SF_LIST* config);
+static CLIENT_APP_RETCODE sip_client_init(const InitClientAppAPI* const init_api, SF_LIST* config);
static void sip_clean();
static CLIENT_APP_RETCODE sip_client_validate(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, Packet* pkt, Detector* userData);
-static CLIENT_APP_RETCODE sip_tcp_client_init(const IniClientAppAPI* const init_api,
+static CLIENT_APP_RETCODE sip_tcp_client_init(const InitClientAppAPI* const init_api,
SF_LIST* config);
static CLIENT_APP_RETCODE sip_tcp_client_validate(const uint8_t* data, uint16_t size,
const int dir, AppIdSession* asd, Packet* pkt, Detector* userData);
char vendor[MAX_VENDOR_SIZE];
};
-static int sip_service_init(const IniServiceAPI* const init_api);
+static int sip_service_init(const InitServiceAPI* const init_api);
static int sip_service_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
0
};
-static CLIENT_APP_RETCODE sip_client_init(const IniClientAppAPI* const init_api, SF_LIST*)
+static CLIENT_APP_RETCODE sip_client_init(const InitClientAppAPI* const init_api, SF_LIST*)
{
unsigned i;
clean_sip_server();
}
-static CLIENT_APP_RETCODE sip_tcp_client_init(const IniClientAppAPI* const init_api,
+static CLIENT_APP_RETCODE sip_tcp_client_init(const InitClientAppAPI* const init_api,
SF_LIST* config)
{
unsigned i;
SipSessionCbServiceProcess(p, headers, dialog, asd);
}
-static int sip_service_init(const IniServiceAPI* const init_api)
+static int sip_service_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&sip_service_validate, IpProtocol::UDP,
(const uint8_t*)SIP_BANNER, SIP_BANNER_LEN, 0, svc_name);
--- /dev/null
+/*
+** Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
+** Copyright (C) 2005-2013 Sourcefire, Inc.
+**
+** 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.
+*/
+
+
+#include "detector_smtp.h"
+
+#include "main/snort_debug.h"
+#include "utils/util.h"
+#include "utils/sflsq.h"
+
+#include "application_ids.h"
+#include "detector_api.h"
+#include "client_plugins/client_app_api.h"
+#include "service_plugins/service_util.h"
+#include "app_info_table.h"
+#include "appid_api.h"
+#include "appid_module.h"
+
+enum SMTPClientState
+{
+ SMTP_CLIENT_STATE_NONE,
+ SMTP_CLIENT_STATE_HELO,
+ SMTP_CLIENT_STATE_MAIL_FROM,
+ SMTP_CLIENT_STATE_RCPT_TO,
+ SMTP_CLIENT_STATE_DATA,
+ SMTP_CLIENT_STATE_MESSAGE,
+ SMTP_CLIENT_STATE_GET_PRODUCT_VERSION,
+ SMTP_CLIENT_STATE_SKIP_LINE,
+ SMTP_CLIENT_STATE_CONNECTION_ERROR,
+ SMTP_CLIENT_STATE_STARTTLS
+};
+
+#define MAX_HEADER_LINE_SIZE 1024
+
+#ifdef UNIT_TESTING
+char* stateName [] =
+{
+ "SMTP_CLIENT_STATE_NONE",
+ "SMTP_CLIENT_STATE_HELO",
+ "SMTP_CLIENT_STATE_MAIL_FROM",
+ "SMTP_CLIENT_STATE_RCPT_TO",
+ "SMTP_CLIENT_STATE_DATA",
+ "SMTP_CLIENT_STATE_MESSAGE",
+ "SMTP_CLIENT_STATE_GET_PRODUCT_VERSION",
+ "SMTP_CLIENT_STATE_SKIP_LINE",
+ "SMTP_CLIENT_STATE_CONNECTION_ERROR",
+ "SMTP_CLIENT_STATE_STARTTLS"
+};
+#endif
+
+/* flag values for ClientSMTPData */
+#define CLIENT_FLAG_STARTTLS_SUCCESS 0x01
+#define CLIENT_FLAG_SMTPS 0x02
+
+#define MAX_VERSION_SIZE 64
+#define SSL_WAIT_PACKETS 8 // This many un-decrypted packets without a HELO and we quit.
+
+struct ClientSMTPData
+{
+ int flags;
+ SMTPClientState state;
+ SMTPClientState nextstate;
+ uint8_t version[MAX_VERSION_SIZE];
+ unsigned pos;
+ uint8_t* headerline;
+ int decryption_countdown;
+};
+
+struct SMTP_CLIENT_APP_CONFIG
+{
+ int enabled;
+};
+
+
+THREAD_LOCAL SMTP_CLIENT_APP_CONFIG smtp_config;
+
+static CLIENT_APP_RETCODE smtp_ca_init(const InitClientAppAPI* const init_api, SF_LIST *config);
+static CLIENT_APP_RETCODE smtp_ca_validate(const uint8_t* data, uint16_t size, const int dir,
+ AppIdSession* asd, Packet* pkt, struct Detector* userData);
+
+static RNAClientAppModule smtp_client_mod =
+{
+ "SMTP", // name
+ IpProtocol::TCP, // proto
+ &smtp_ca_init, // init
+ nullptr, // clean
+ &smtp_ca_validate, // validate
+ 1, // minimum_matches
+ nullptr, // api
+ nullptr, // userData
+ 0, // precedence
+ nullptr, // finalize,
+ 1, // provides_user
+ 0 // flow_data_index
+};
+
+struct Client_App_Pattern
+{
+ const uint8_t* pattern;
+ unsigned length;
+ int index;
+ unsigned appId;
+};
+
+#define HELO "HELO "
+#define EHLO "EHLO "
+#define MAILFROM "MAIL FROM:"
+#define RCPTTO "RCPT TO:"
+#define DATA "DATA"
+#define RSET "RSET"
+#define AUTH "AUTH PLAIN"
+#define STARTTLS "STARTTLS"
+
+#define STARTTLS_COMMAND_SUCCESS "220 "
+
+#define MICROSOFT "Microsoft "
+#define OUTLOOK "Outlook"
+#define EXPRESS "Express "
+#define IMO "IMO, "
+
+#define XMAILER "X-Mailer: "
+#define USERAGENT "User-Agent: "
+
+static const uint8_t APP_SMTP_OUTLOOK[] = "Microsoft Outlook";
+static const uint8_t APP_SMTP_OUTLOOK_EXPRESS[] = "Microsoft Outlook Express ";
+static const uint8_t APP_SMTP_IMO[] = "IMO, ";
+static const uint8_t APP_SMTP_EVOLUTION[] = "Ximian Evolution ";
+static const uint8_t APP_SMTP_LOTUS_NOTES[] = "Lotus Notes ";
+static const uint8_t APP_SMTP_APPLEMAIL[] = "Apple Mail (";
+static const uint8_t APP_SMTP_EUDORA[] = "QUALCOMM Windows Eudora Version ";
+static const uint8_t APP_SMTP_EUDORAPRO[] = "Windows Eudora Pro Version ";
+static const uint8_t APP_SMTP_AOL[] = "AOL ";
+static const uint8_t APP_SMTP_MUTT[] = "Mutt/";
+static const uint8_t APP_SMTP_KMAIL[] = "KMail/";
+static const uint8_t APP_SMTP_MTHUNDERBIRD[] = "Mozilla Thunderbird ";
+static const uint8_t APP_SMTP_THUNDERBIRD[] = "Thunderbird ";
+static const uint8_t APP_SMTP_MOZILLA[] = "Mozilla";
+static const uint8_t APP_SMTP_THUNDERBIRD_SHORT[] = "Thunderbird/";
+
+static Client_App_Pattern patterns[] =
+{
+ {(uint8_t*)HELO, sizeof(HELO)-1, -1, APP_ID_SMTP},
+ {(uint8_t*)EHLO, sizeof(EHLO)-1, -1, APP_ID_SMTP},
+ {APP_SMTP_OUTLOOK, sizeof(APP_SMTP_OUTLOOK)-1, -1, APP_ID_OUTLOOK},
+ {APP_SMTP_OUTLOOK_EXPRESS, sizeof(APP_SMTP_OUTLOOK_EXPRESS)-1,-1, APP_ID_OUTLOOK_EXPRESS},
+ {APP_SMTP_IMO, sizeof(APP_SMTP_IMO)-1, -1, APP_ID_SMTP_IMO},
+ {APP_SMTP_EVOLUTION, sizeof(APP_SMTP_EVOLUTION)-1, -1, APP_ID_EVOLUTION},
+ {APP_SMTP_LOTUS_NOTES, sizeof(APP_SMTP_LOTUS_NOTES)-1, -1, APP_ID_LOTUS_NOTES},
+ {APP_SMTP_APPLEMAIL, sizeof(APP_SMTP_APPLEMAIL)-1, -1, APP_ID_APPLE_EMAIL},
+ {APP_SMTP_EUDORA, sizeof(APP_SMTP_EUDORA)-1, -1, APP_ID_EUDORA},
+ {APP_SMTP_EUDORAPRO, sizeof(APP_SMTP_EUDORAPRO)-1, -1, APP_ID_EUDORA_PRO},
+ {APP_SMTP_AOL, sizeof(APP_SMTP_AOL)-1, -1, APP_ID_AOL_EMAIL},
+ {APP_SMTP_MUTT, sizeof(APP_SMTP_MUTT)-1, -1, APP_ID_MUTT},
+ {APP_SMTP_KMAIL, sizeof(APP_SMTP_KMAIL)-1, -1, APP_ID_KMAIL},
+ {APP_SMTP_MTHUNDERBIRD, sizeof(APP_SMTP_MTHUNDERBIRD)-1, -1, APP_ID_THUNDERBIRD},
+ {APP_SMTP_THUNDERBIRD, sizeof(APP_SMTP_THUNDERBIRD)-1, -1, APP_ID_THUNDERBIRD},
+};
+
+static AppRegistryEntry clientAppIdRegistry[] =
+{
+ {APP_ID_THUNDERBIRD, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_OUTLOOK, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_KMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_EUDORA_PRO, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_EVOLUTION, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_SMTP_IMO, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_EUDORA, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_LOTUS_NOTES, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_APPLE_EMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_AOL_EMAIL, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_MUTT, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_SMTP, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_OUTLOOK_EXPRESS, APPINFO_FLAG_CLIENT_ADDITIONAL},
+ {APP_ID_SMTPS, APPINFO_FLAG_CLIENT_ADDITIONAL}
+};
+
+static CLIENT_APP_RETCODE smtp_ca_init(const InitClientAppAPI* const init_api, SF_LIST* config)
+{
+ unsigned i;
+
+ smtp_config.enabled = 1;
+
+ if (config)
+ {
+ SF_LNODE* cursor;
+ RNAClientAppModuleConfigItem* item;
+
+ for (item = (RNAClientAppModuleConfigItem*)sflist_first(config, &cursor);
+ item;
+ item = (RNAClientAppModuleConfigItem*)sflist_next(&cursor))
+ {
+ DebugFormat(DEBUG_LOG,"Processing %s: %s\n",item->name, item->value);
+ if (strcasecmp(item->name, "enabled") == 0)
+ {
+ smtp_config.enabled = atoi(item->value);
+ }
+ }
+ }
+
+ if (smtp_config.enabled)
+ {
+ for (i=0; i < sizeof(patterns)/sizeof(*patterns); i++)
+ {
+ init_api->RegisterPattern(&smtp_ca_validate, IpProtocol::TCP, patterns[i].pattern,
+ patterns[i].length, patterns[i].index);
+ }
+ }
+
+ unsigned j;
+ for (j=0; j < sizeof(clientAppIdRegistry)/sizeof(*clientAppIdRegistry); j++)
+ {
+ DebugFormat(DEBUG_LOG,"registering appId: %d\n",clientAppIdRegistry[j].appId);
+ init_api->RegisterAppId(&smtp_ca_validate, clientAppIdRegistry[j].appId,
+ clientAppIdRegistry[j].additionalInfo);
+ }
+
+ return CLIENT_APP_SUCCESS;
+}
+
+#define SMTP_PORT 25
+#define SMTPS_DEPRECATED_PORT 465
+#define SMTP_CLOSING_CONN "closing connection\x0d\x0a"
+
+enum SMTPServiceState
+{
+ SMTP_SERVICE_STATE_CONNECTION,
+ SMTP_SERVICE_STATE_HELO,
+ SMTP_SERVICE_STATE_TRANSFER,
+ SMTP_SERVICE_STATE_CONNECTION_ERROR,
+ SMTP_SERVICE_STATE_STARTTLS,
+ SMTP_SERVICE_STATE_SSL_HANDSHAKE
+};
+
+struct ServiceSMTPData
+{
+ SMTPServiceState state;
+ int code;
+ int multiline;
+ int set_flags;
+ bool detected;
+};
+
+#pragma pack(1)
+
+struct ServiceSMTPCode
+{
+ uint8_t code[3];
+ uint8_t sp;
+};
+
+#pragma pack()
+
+static int smtp_svc_init(const InitServiceAPI* const init_api);
+static int smtp_svc_validate(ServiceValidationArgs* args);
+
+static const RNAServiceElement svc_element =
+{
+ nullptr,
+ &smtp_svc_validate,
+ nullptr,
+ DETECTOR_TYPE_DECODER,
+ 1,
+ 1,
+ 0,
+ "smtp"
+};
+
+static RNAServiceValidationPort pp[] =
+{
+ {&smtp_svc_validate, SMTP_PORT, IpProtocol::TCP, 0},
+ {&smtp_svc_validate, SMTPS_DEPRECATED_PORT, IpProtocol::TCP, 0},
+ { nullptr, 0, IpProtocol::PROTO_NOT_SET, 0 }
+};
+
+static RNAServiceValidationModule smtp_service_mod =
+{
+ "SMTP",
+ &smtp_svc_init,
+ pp,
+ nullptr,
+ nullptr,
+ 0,
+ nullptr,
+ 0
+};
+
+static AppRegistryEntry appIdRegistry[] =
+{
+ {APP_ID_SMTP, 0},
+ {APP_ID_SMTPS, 0}
+};
+
+struct SMTPDetectorData
+{
+ ClientSMTPData client;
+ ServiceSMTPData server;
+ int need_continue;
+ int watch_for_deprecated_port;
+};
+
+SO_PUBLIC RNADetectorValidationModule smtp_detector_mod =
+{
+ &smtp_service_mod,
+ &smtp_client_mod,
+ nullptr,
+ 0
+};
+
+static int smtp_svc_init(const InitServiceAPI* const init_api)
+{
+ const char SMTP_PATTERN1[] = "220 ";
+ const char SMTP_PATTERN2[] = "220-";
+ const char SMTP_PATTERN3[] = "SMTP";
+ const char SMTP_PATTERN4[] = "smtp";
+
+ init_api->RegisterPattern(&smtp_svc_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN1,
+ sizeof(SMTP_PATTERN1) - 1, 0, "smtp");
+ init_api->RegisterPattern(&smtp_svc_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN2,
+ sizeof(SMTP_PATTERN2) - 1, 0, "smtp");
+ init_api->RegisterPattern(&smtp_svc_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN3,
+ sizeof(SMTP_PATTERN3) - 1, -1, "smtp");
+ init_api->RegisterPattern(&smtp_svc_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN4,
+ sizeof(SMTP_PATTERN4) - 1, -1, "smtp");
+
+ unsigned i;
+ for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
+ {
+ DebugFormat(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
+ init_api->RegisterAppId(&smtp_svc_validate, appIdRegistry[i].appId,
+ appIdRegistry[i].additionalInfo);
+ }
+
+ return 0;
+}
+
+/*
+ * product - The product data should not include any characters
+ * after the end of the product version (e.g. no CR, LF, etc).
+ * prefix_len - The number of characters that are the prefix to the version,
+ * including the NUL terminating character.
+ */
+static int extract_version_and_add_client_app(ApplicationId clientId, const int prefix_len,
+ const uint8_t* product, const uint8_t* product_end, ClientSMTPData* const client_data,
+ AppIdSession* asd, AppId appId, PegCount* stat_counter)
+{
+ const uint8_t* p;
+ uint8_t* v;
+ uint8_t* v_end;
+
+ v_end = client_data->version;
+ v_end += MAX_VERSION_SIZE - 1;
+
+ // The prefix_len includes the NUL character, but product does not, so
+ // subtract 1 from length to skip.
+ p = product + prefix_len - 1;
+ if (p >= product_end || isspace(*p))
+ return 1;
+ for (v=client_data->version; v<v_end && p < product_end; v++,p++)
+ {
+ *v = *p;
+ }
+ *v = 0;
+ smtp_client_mod.api->add_app(asd, appId, clientId, (char*)client_data->version);
+ (*stat_counter)++;
+ return 0;
+}
+
+
+/*
+ * Identify the product and version of the SMTP client.
+ *
+ * Returns 0 if a recognized product is found. Otherwise returns 1.
+ */
+static int IdentifyClientVersion(ClientSMTPData* const fd, const uint8_t* product,
+ const uint8_t* data_end, AppIdSession* asd, Packet*)
+{
+ const uint8_t* p;
+ uint8_t* v;
+ uint8_t* v_end;
+ unsigned len;
+ unsigned sublen;
+ AppId appId = (fd->flags & CLIENT_FLAG_SMTPS) ? APP_ID_SMTPS : APP_ID_SMTP;
+
+ v_end = fd->version;
+ v_end += MAX_VERSION_SIZE - 1;
+ len = data_end - product;
+ if (len >= sizeof(MICROSOFT) && memcmp(product, MICROSOFT, sizeof(MICROSOFT)-1) == 0)
+ {
+ p = product + sizeof(MICROSOFT) - 1;
+
+ if (data_end-p >= (int)sizeof(OUTLOOK) && memcmp(p, OUTLOOK, sizeof(OUTLOOK)-1) == 0)
+ {
+ p += sizeof(OUTLOOK) - 1;
+ if (p >= data_end)
+ return 1;
+ if (*p == ',')
+ {
+ p++;
+ if (p >= data_end || *p != ' ')
+ return 1;
+ return extract_version_and_add_client_app(APP_ID_OUTLOOK,
+ 2, p, data_end, fd, asd, appId,
+ &appid_stats.smtp_microsoft_outlook_clients);
+ }
+ else if (*p == ' ')
+ {
+ 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,
+ &appid_stats.smtp_microsoft_outlook_express_clients);
+ }
+ 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,
+ &appid_stats.smtp_microsoft_outlook_imo_clients);
+ }
+ }
+ }
+ }
+ else if (len >= sizeof(APP_SMTP_EVOLUTION) && memcmp(product, APP_SMTP_EVOLUTION,
+ 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,
+ &appid_stats.smtp_evolution_clients);
+ }
+ 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,
+ &appid_stats.smtp_lotus_notes_clients);
+ }
+ else if (len >= sizeof(APP_SMTP_APPLEMAIL) && memcmp(product, APP_SMTP_APPLEMAIL,
+ sizeof(APP_SMTP_APPLEMAIL)-1) == 0)
+ {
+ p = product + sizeof(APP_SMTP_APPLEMAIL) - 1;
+ if (p >= data_end || *(data_end - 1) != ')' || *p == ')' || isspace(*p))
+ return 1;
+ for (v=fd->version; v<v_end && p < data_end-1; v++,p++)
+ {
+ *v = *p;
+ }
+ *v = 0;
+ smtp_client_mod.api->add_app(asd, appId, APP_ID_APPLE_EMAIL, (char*)fd->version);
+ appid_stats.smtp_applemail_clients++;
+ 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,
+ &appid_stats.smtp_eudora_clients);
+ }
+ 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,
+ &appid_stats.smtp_eudora_pro_clients);
+ }
+ 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,
+ &appid_stats.smtp_aol_clients);
+ }
+ 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,
+ &appid_stats.smtp_mutt_clients);
+ }
+ 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,
+ &appid_stats.smtp_kmail_clients);
+ }
+ 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,
+ &appid_stats.smtp_thunderbird_clients);
+ }
+ 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,
+ &appid_stats.smtp_thunderbird_clients);
+ }
+ else if (len >= sizeof(APP_SMTP_MOZILLA) && memcmp(product, APP_SMTP_MOZILLA,
+ sizeof(APP_SMTP_MOZILLA)-1) == 0)
+ {
+ for (p = product + sizeof(APP_SMTP_MOZILLA) - 1; p < data_end; p++)
+ {
+ if (*p == 'T')
+ {
+ sublen = data_end - p;
+ if (sublen >= sizeof(APP_SMTP_THUNDERBIRD_SHORT) && memcmp(p,
+ APP_SMTP_THUNDERBIRD_SHORT, sizeof(APP_SMTP_THUNDERBIRD_SHORT)-1) == 0)
+ {
+ return extract_version_and_add_client_app(
+ APP_ID_THUNDERBIRD, sizeof(APP_SMTP_THUNDERBIRD_SHORT),
+ p, data_end, fd, asd, appId,
+ &appid_stats.smtp_thunderbird_clients);
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+static void smtp_free_state(void *data)
+{
+ SMTPDetectorData* dd = (SMTPDetectorData*)data;
+ ClientSMTPData *cd;
+
+ if (dd)
+ {
+ cd = &dd->client;
+ if (cd->headerline)
+ snort_free(cd->headerline);
+ snort_free(dd);
+ }
+}
+static inline SMTPDetectorData* smtp_get_SMTPDetectorData(AppIdSession* asd)
+{
+ SMTPDetectorData* dd = (SMTPDetectorData*)smtp_detector_mod.api->data_get(asd, smtp_detector_mod.flow_data_index);
+ if (dd)
+ return dd;
+
+ dd = (SMTPDetectorData*)snort_calloc(1, sizeof(*dd));
+ if (smtp_detector_mod.api->data_add(asd, dd, smtp_detector_mod.flow_data_index, &smtp_free_state))
+ {
+ snort_free(dd);
+ return nullptr;
+ }
+
+ dd->server.state = SMTP_SERVICE_STATE_CONNECTION;
+ dd->server.detected = false;
+ dd->client.state = SMTP_CLIENT_STATE_HELO;
+ dd->need_continue = 1;
+ dd->watch_for_deprecated_port = 1;
+
+ asd->set_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
+ return dd;
+}
+
+// #define UNIT_TEST_SKIP
+static CLIENT_APP_RETCODE smtp_ca_validate(const uint8_t* data, uint16_t size, const int dir,
+ AppIdSession* asd, Packet* pkt, struct Detector*)
+{
+ SMTPDetectorData* dd;
+ ClientSMTPData* fd;
+ const uint8_t* end;
+ unsigned len;
+#ifdef UNIT_TESTING
+ SMTPClientState currState = SMTP_CLIENT_STATE_NONE;
+#endif
+
+ if (!(dd = smtp_get_SMTPDetectorData(asd)))
+ return CLIENT_APP_ENOMEM;
+
+ fd = &dd->client;
+
+ if (dir != APP_ID_FROM_INITIATOR)
+ return CLIENT_APP_INPROCESS;
+
+ if (asd->get_session_flags(APPID_SESSION_ENCRYPTED | APPID_SESSION_DECRYPTED) == APPID_SESSION_ENCRYPTED)
+ {
+ if ((fd->flags & CLIENT_FLAG_STARTTLS_SUCCESS))
+ {
+ fd->decryption_countdown--;
+ if (!fd->decryption_countdown)
+#ifdef UNIT_TEST_SKIP
+ if (asd->session_packet_count == 0)
+#endif
+ {
+ fd->flags |= CLIENT_FLAG_SMTPS; // report as SMTPS
+ asd->clear_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
+ /* 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. */
+ smtp_client_mod.api->add_app(asd, APP_ID_SMTPS, APP_ID_SMTPS, nullptr);
+ goto done;
+ }
+ }
+ return CLIENT_APP_INPROCESS;
+ }
+
+
+ for (end = data + size; data < end; data++)
+ {
+#ifdef UNIT_TESTING
+ if (app_id_debug_session_flag && currState != fd->state)
+ {
+ DEBUG_WRAP(DebugMessage(DEBUG_APPID, "AppIdDbg %s SMTP client state %s\n", app_id_debug_session, stateName[fd->state]););
+ currState = fd->state;
+ }
+#endif
+ len = end - data;
+ switch (fd->state)
+ {
+ case SMTP_CLIENT_STATE_HELO:
+ if (len >= (sizeof(HELO)-1) && strncasecmp((const char*)data, HELO, sizeof(HELO)-1) == 0)
+ {
+ data += (sizeof(HELO)-1)-1;
+ fd->nextstate = SMTP_CLIENT_STATE_MAIL_FROM;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else if (len >= (sizeof(EHLO)-1) && strncasecmp((const char*)data, EHLO, sizeof(EHLO)-1) == 0)
+ {
+ data += (sizeof(EHLO)-1)-1;
+ fd->nextstate = SMTP_CLIENT_STATE_MAIL_FROM;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else goto done;
+ break;
+
+ case SMTP_CLIENT_STATE_MAIL_FROM:
+ if (len >= (sizeof(MAILFROM)-1) && strncasecmp((const char*)data, MAILFROM, sizeof(MAILFROM)-1) == 0)
+ {
+ data += (sizeof(MAILFROM)-1)-1;
+ fd->nextstate = SMTP_CLIENT_STATE_RCPT_TO;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else if (len >= (sizeof(RSET)-1) && strncasecmp((const char*)data, RSET, sizeof(RSET)-1) == 0)
+ {
+ data += (sizeof(RSET)-1)-1;
+ fd->nextstate = fd->state;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else if (len >= (sizeof(AUTH)-1) && strncasecmp((const char*)data, AUTH, sizeof(AUTH)-1) == 0)
+ {
+ data += (sizeof(AUTH)-1)-1;
+ fd->nextstate = fd->state;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else if (len >= (sizeof(STARTTLS)-1) && strncasecmp((const char*)data, STARTTLS, sizeof(STARTTLS)-1) == 0)
+ {
+ data += (sizeof(STARTTLS)-1)-1;
+ dd->server.state = SMTP_SERVICE_STATE_STARTTLS;
+ fd->nextstate = fd->state;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else goto done;
+ break;
+ case SMTP_CLIENT_STATE_RCPT_TO:
+ if (len >= (sizeof(RCPTTO)-1) && strncasecmp((const char*)data, RCPTTO, sizeof(RCPTTO)-1) == 0)
+ {
+ data += (sizeof(RCPTTO)-1)-1;
+ fd->nextstate = SMTP_CLIENT_STATE_DATA;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else
+ goto done;
+ break;
+
+ case SMTP_CLIENT_STATE_DATA:
+ if (len >= (sizeof(DATA)-1) && strncasecmp((const char*)data, DATA, sizeof(DATA)-1) == 0)
+ {
+ data += (sizeof(DATA)-1)-1;
+ fd->nextstate = SMTP_CLIENT_STATE_MESSAGE;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ else if (len >= (sizeof(RCPTTO)-1) && strncasecmp((const char*)data, RCPTTO, sizeof(RCPTTO)-1) == 0)
+ {
+ data += (sizeof(RCPTTO)-1)-1;
+ fd->nextstate = fd->state;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ break;
+ case SMTP_CLIENT_STATE_MESSAGE:
+ if (*data == '.')
+ {
+ if (len == 0 ||
+ (len >= 1 && data[1] == '\n') ||
+ (len >= 2 && data[1] == '\r' && data[2] == '\n'))
+ {
+ smtp_client_mod.api->add_app(asd, APP_ID_SMTP, APP_ID_SMTP, nullptr);
+ goto done;
+ }
+ }
+ else if (len >= (sizeof(XMAILER)-1) && strncasecmp((const char*)data, XMAILER, sizeof(XMAILER)-1) == 0)
+ {
+ data += (sizeof(XMAILER)-1)-1;
+ fd->state = SMTP_CLIENT_STATE_GET_PRODUCT_VERSION;
+ }
+ else if (len >= (sizeof(USERAGENT)-1) && strncasecmp((const char*)data, USERAGENT, sizeof(USERAGENT)-1) == 0)
+ {
+ data += (sizeof(USERAGENT)-1)-1;
+ fd->state = SMTP_CLIENT_STATE_GET_PRODUCT_VERSION;
+ }
+ else if (!isprint(*data) && *data != '\t')
+ goto done;
+ else
+ {
+ fd->nextstate = fd->state;
+ fd->state = SMTP_CLIENT_STATE_SKIP_LINE;
+ }
+ break;
+
+ case SMTP_CLIENT_STATE_GET_PRODUCT_VERSION:
+ if (*data == '\r')
+ {
+ if (fd->headerline && fd->pos)
+ {
+ IdentifyClientVersion(fd, fd->headerline, fd->headerline + fd->pos, asd, pkt);
+ snort_free(fd->headerline);
+ fd->headerline = nullptr;
+ fd->pos = 0;
+ }
+ goto done;
+ }
+ else if (!isprint(*data))
+ {
+ snort_free(fd->headerline);
+ fd->headerline = nullptr;
+ fd->pos = 0;
+ goto done;
+ }
+ else
+ {
+ if (!fd->headerline)
+ fd->headerline = (uint8_t*)snort_alloc(MAX_HEADER_LINE_SIZE);
+
+ if (fd->pos < (MAX_HEADER_LINE_SIZE-1))
+ fd->headerline[fd->pos++] = *data;
+ }
+ break;
+
+ case SMTP_CLIENT_STATE_SKIP_LINE:
+ if (*data == '\n')
+ {
+ fd->pos = 0;
+ fd->state = fd->nextstate;
+ fd->nextstate = SMTP_CLIENT_STATE_NONE;
+ }
+ else if (!(*data == '\r' || isprint(*data)))
+ goto done;
+ break;
+
+ default:
+ goto done;
+ }
+ }
+ return CLIENT_APP_INPROCESS;
+
+done:
+ dd->need_continue = 0;
+ asd->set_session_flags(APPID_SESSION_CLIENT_DETECTED);
+ return CLIENT_APP_SUCCESS;
+}
+
+static inline int smtp_validate_reply(const uint8_t*data, uint16_t* offset, uint16_t size,
+ int* multi, int* code)
+{
+ const ServiceSMTPCode* code_hdr;
+ int tmp;
+
+ // Trim any blank lines (be a little tolerant)
+ for (; *offset<size; (*offset)++)
+ {
+ if (data[*offset] != 0x0D && data[*offset] != 0x0A)
+ break;
+ }
+
+ if (size - *offset < (int)sizeof(ServiceSMTPCode))
+ {
+ for (; *offset<size; (*offset)++)
+ {
+ if (!isspace(data[*offset]))
+ return -1;
+ }
+ return 0;
+ }
+
+ code_hdr = (ServiceSMTPCode* )(data + *offset);
+
+ if (code_hdr->code[0] < '1' || code_hdr->code[0] > '5')
+ return -1;
+ tmp = (code_hdr->code[0] - '0') * 100;
+
+ if (code_hdr->code[1] < '0' || code_hdr->code[1] > '5')
+ return -1;
+ tmp += (code_hdr->code[1] - '0') * 10;
+
+ if (!isdigit(code_hdr->code[2]))
+ return -1;
+ tmp += code_hdr->code[2] - '0';
+
+ if (*multi && tmp != *code)
+ return -1;
+ *code = tmp;
+ if (code_hdr->sp == '-') *multi = 1;
+ else if (code_hdr->sp == ' ')
+ *multi = 0;
+ else
+ return -1;
+
+ // We have a valid code, now we need to see if the rest of the line is okay
+ *offset += sizeof(ServiceSMTPCode);
+ for (; *offset < size; (*offset)++)
+ {
+ if (data[*offset] == 0x0D)
+ {
+ (*offset)++;
+ if (*offset >= size)
+ return -1;
+ if (data[*offset] != 0x0A)
+ return -1;
+ }
+
+ if (data[*offset] == 0x0A)
+ {
+ if (*multi)
+ {
+ if ((*offset + 1) >= size)
+ return 0;
+
+ if (size - (*offset + 1) < (int)sizeof(ServiceSMTPCode))
+ return -1;
+
+ code_hdr = (ServiceSMTPCode*)(data + *offset + 1);
+
+ if (code_hdr->code[0] < '1' || code_hdr->code[0] > '5')
+ return -1;
+ tmp = (code_hdr->code[0] - '0') * 100;
+
+ if (code_hdr->code[1] < '1' || code_hdr->code[1] > '5')
+ return -1;
+ tmp += (code_hdr->code[1] - '0') * 10;
+
+ if (!isdigit(code_hdr->code[2]))
+ return -1;
+ tmp += code_hdr->code[2] - '0';
+
+ if (tmp != *code)
+ return -1;
+
+ if (code_hdr->sp == ' ') *multi = 0;
+ else if (code_hdr->sp != '-')
+ return -1;
+
+ *offset += sizeof(ServiceSMTPCode);
+ }
+ else
+ {
+ (*offset)++;
+ return *code;
+ }
+ }
+ else if (!isprint(data[*offset]))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int smtp_svc_validate(ServiceValidationArgs* args)
+{
+ SMTPDetectorData* dd;
+ ServiceSMTPData* fd;
+ AppIdSession* asd = args->asd;
+ const uint8_t* data = args->data;
+ uint16_t size = args->size;
+ uint16_t offset;
+
+ if (!(dd = smtp_get_SMTPDetectorData(asd)))
+ return SERVICE_ENOMEM;
+
+ if (!size)
+ goto inprocess;
+
+ // Whether this is bound for the client detector or not, if client doesn't care
+ // then clear the APPID_SESSION_CONTINUE flag and we will be done sooner.
+ if (dd->need_continue == 0)
+ {
+ dd->need_continue--; // don't come through again.
+ asd->clear_session_flags(APPID_SESSION_CONTINUE);
+ if (dd->client.flags & CLIENT_FLAG_SMTPS)
+ {
+ // client side gave up because everything is encrypted.
+ smtp_service_mod.api->add_service(asd, args->pkt, args->dir, &svc_element,
+ APP_ID_SMTPS, nullptr, nullptr, nullptr);
+ return SERVICE_SUCCESS;
+ }
+ else if (asd->get_session_flags(APPID_SESSION_SERVICE_DETECTED))
+ {
+ // Client made it's decision so we are totally done.
+ return SERVICE_SUCCESS;
+ }
+ // We arrive here because the service side is not done yet.
+ }
+
+ if (args->dir != APP_ID_FROM_RESPONDER)
+ goto inprocess; // allow client validator to have it's shot.
+
+ if (dd->watch_for_deprecated_port)
+ {
+ dd->watch_for_deprecated_port = 0;
+ // If we have caught a response on port 465 that isn't encrypted+decrypted it isn't SMTP at all.
+ // The new IANA assignment for this port is non-SSL and NOT SMTP. Only an old server will survive the test.
+ if (args->pkt->ptrs.sp == SMTPS_DEPRECATED_PORT && !asd->get_session_flags(APPID_SESSION_DECRYPTED))
+ {
+ // This is not an SMTPS port because we have not ALREADY gone through the SSL handshake
+ goto fail;
+ }
+ }
+
+ fd = &dd->server;
+
+ offset = 0;
+ while (offset < size)
+ {
+ if (smtp_validate_reply(data, &offset, size, &fd->multiline, &fd->code) < 0)
+ {
+ if (!(dd->client.flags & CLIENT_FLAG_STARTTLS_SUCCESS))
+ goto fail;
+ goto inprocess;
+ }
+ if (!fd->code) goto inprocess;
+ switch (fd->state)
+ {
+ case SMTP_SERVICE_STATE_CONNECTION:
+ switch (fd->code)
+ {
+ case 220:
+ fd->state = SMTP_SERVICE_STATE_HELO;
+ break;
+ case 421:
+ if (service_strstr(data, size, (const uint8_t*)SMTP_CLOSING_CONN, sizeof(SMTP_CLOSING_CONN)-1))
+ goto success;
+ case 520:
+ case 554:
+ fd->state = SMTP_SERVICE_STATE_CONNECTION_ERROR;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+ case SMTP_SERVICE_STATE_HELO:
+ switch (fd->code)
+ {
+ case 250:
+ fd->state = SMTP_SERVICE_STATE_TRANSFER;
+ break;
+ case 500:
+ case 501:
+ case 504:
+ break;
+ case 421:
+ case 553:
+ fd->state = SMTP_SERVICE_STATE_CONNECTION_ERROR;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+ case SMTP_SERVICE_STATE_STARTTLS:
+ // success or fail, return client to connection-complete state.
+ dd->client.state = SMTP_CLIENT_STATE_HELO;
+ fd->state = SMTP_SERVICE_STATE_HELO;
+ if (fd->code == 220)
+ {
+ asd->set_session_flags(APPID_SESSION_ENCRYPTED);
+ // Now we wonder if the decryption mechanism is in place, so...
+ dd->client.flags |= CLIENT_FLAG_STARTTLS_SUCCESS;
+ dd->client.decryption_countdown = SSL_WAIT_PACKETS; // start a countdown
+ goto inprocess;
+ }
+ /* STARTTLS failed. */
+ break;
+ case SMTP_SERVICE_STATE_TRANSFER:
+ goto success;
+ case SMTP_SERVICE_STATE_CONNECTION_ERROR:
+ default:
+ goto fail;
+ }
+ }
+
+inprocess:
+ smtp_service_mod.api->service_inprocess(asd, args->pkt, args->dir, &svc_element);
+ return SERVICE_INPROCESS;
+
+success:
+ if (dd->need_continue > 0)
+ asd->set_session_flags(APPID_SESSION_CONTINUE);
+
+ smtp_service_mod.api->add_service(asd, args->pkt, args->dir, &svc_element,
+ APP_ID_SMTP, nullptr, nullptr, nullptr);
+ if (!fd->detected)
+ {
+ if(fd->state == SMTP_SERVICE_STATE_STARTTLS)
+ appid_stats.smtps_flows++;
+ else
+ appid_stats.smtp_flows++;
+ fd->detected = true;
+ }
+ return SERVICE_SUCCESS;
+
+fail:
+ smtp_service_mod.api->fail_service(asd, args->pkt, args->dir, &svc_element,
+ smtp_service_mod.flow_data_index);
+ return SERVICE_NOMATCH;
+}
#include "detector_plugins/detector_api.h"
-extern RNAServiceValidationModule smtp_service_mod;
+extern RNADetectorValidationModule smtp_detector_mod;
+
#endif
add_library(smtp_test_depends_on_lib ../../appid_stats_counter.cc)
-add_cpputest(client_app_smtp_test smtp_test_depends_on_lib ${SMTP_TEST_LIBS})
+add_cpputest(detector_smtp_test smtp_test_depends_on_lib ${SMTP_TEST_LIBS})
include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
--- /dev/null
+
+AM_DEFAULT_SOURCE_EXT = .cc
+
+check_PROGRAMS = \
+detector_smtp_test
+
+TESTS = $(check_PROGRAMS)
+
+detector_smtp_test_CPPFLAGS = -I$(top_srcdir)/src/network_inspectors/appid @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
+
+detector_smtp_test_LDADD = \
+../../appid_stats_counter.o \
+../../../../utils/libutils.a \
+@CPPUTEST_LDFLAGS@
+
// client_app_smtp_test.cc author Steve Chew <stechew@cisco.com>
// unit test for client_app_smtp
-#include "network_inspectors/appid/client_plugins/client_app_smtp.cc"
+#include "network_inspectors/appid/detector_plugins/detector_smtp.cc"
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
uint precedence;
CHPListElement* chpa;
CHPApp* chpapp;
+ AppInfoManager& app_info_mgr = AppInfoManager::get_instance();
//find the CHP App for this
if (!(chpapp = (decltype(chpapp))sfxhash_find(CHP_glossary, &appIdInstance)))
{
ErrorMessage(
- "LuaDetectorApi:Invalid attempt to add a CHP action for unknown appId %d, instance %d. - pattern:\"%s\" - action \"%s\"",
+ "LuaDetectorApi:Invalid attempt to add a CHP action for unknown appId %d, instance %d. - pattern:\"%s\" - action \"%s\"\n",
CHP_APPIDINSTANCE_TO_ID(appIdInstance), CHP_APPIDINSTANCE_TO_INSTANCE(appIdInstance),
patternData, optionalActionData ? optionalActionData : "");
snort_free(patternData);
precedence = chpapp->ptype_scan_counts[patternType]++;
// at runtime we'll want to know how many of each type of pattern we are looking for.
if (actionType == REWRITE_FIELD || actionType == INSERT_FIELD)
- chpapp->ptype_rewrite_insert_used[patternType]=1; // true.
- else if (actionType != ALTERNATE_APPID)
+ {
+ if (!app_info_mgr.get_app_info_flags(CHP_APPIDINSTANCE_TO_ID(appIdInstance), APPINFO_FLAG_SUPPORTED_SEARCH))
+ {
+ ErrorMessage( "LuaDetectorApi: CHP action type, %d, requires previous use of action type, %d, (see appId %d, pattern=\"%s\").\n",
+ actionType, GET_OFFSETS_FROM_REBUILT,
+ CHP_APPIDINSTANCE_TO_ID(appIdInstance), patternData);
+ snort_free(patternData);
+ if (optionalActionData)
+ snort_free(optionalActionData);
+ return 0;
+ }
+ switch (patternType)
+ {
+ // permitted pattern type (modifiable HTTP/SPDY request field)
+ case AGENT_PT:
+ case HOST_PT:
+ case REFERER_PT:
+ case URI_PT:
+ case COOKIE_PT:
+ break;
+ default:
+ ErrorMessage( "LuaDetectorApi: CHP action type, %d, on unsupported pattern type, %d, (see appId %d, pattern=\"%s\").\n",
+ actionType, patternType, CHP_APPIDINSTANCE_TO_ID(appIdInstance), patternData);
+ snort_free(patternData);
+ if (optionalActionData)
+ snort_free(optionalActionData);
+ return 0;
+ }
+ }
+ else if (actionType != ALTERNATE_APPID && actionType != DEFER_TO_SIMPLE_DETECT)
chpapp->ptype_req_counts[patternType]++;
chpa = (CHPListElement*)snort_calloc(sizeof(CHPListElement));
if (actionType == GET_OFFSETS_FROM_REBUILT)
{
/* This is a search engine and it is SUPPORTED for safe-search packet rewrite */
- AppInfoManager::get_instance().set_app_info_flags(CHP_APPIDINSTANCE_TO_ID(appIdInstance), APPINFO_FLAG_SEARCH_ENGINE |
+ app_info_mgr.set_app_info_flags(CHP_APPIDINSTANCE_TO_ID(appIdInstance), APPINFO_FLAG_SEARCH_ENGINE |
APPINFO_FLAG_SUPPORTED_SEARCH);
}
else if (actionType == SEARCH_UNSUPPORTED)
{
/* This is a search engine and it is UNSUPPORTED for safe-search packet rewrite */
- AppInfoManager::get_instance().set_app_info_flags(CHP_APPIDINSTANCE_TO_ID(appIdInstance), APPINFO_FLAG_SEARCH_ENGINE);
+ app_info_mgr.set_app_info_flags(CHP_APPIDINSTANCE_TO_ID(appIdInstance), APPINFO_FLAG_SEARCH_ENGINE);
}
+ else if (actionType == DEFER_TO_SIMPLE_DETECT && strcmp(patternData,"<ignore-all-patterns>") == 0)
+ {
+ remove_http_patterns_for_id(appIdInstance);
+ }
+
return 0;
}
AppIdConfig* pAppidConfig; ///< AppId context for which this API should be used
};
-struct IniServiceAPI;
-using RNAServiceValidationInitFCN = int(*)(const IniServiceAPI* const);
+struct InitServiceAPI;
+using RNAServiceValidationInitFCN = int(*)(const InitServiceAPI* const);
using RNAServiceValidationCleanFCN = void(*)();
struct RNAServiceValidationPort;
struct RNAServiceValidationModule;
-struct IniServiceAPI
+struct InitServiceAPI
{
void (* RegisterPattern)( RNAServiceValidationFCN, IpProtocol proto, const uint8_t* pattern,
unsigned size, int position, const char* name);
#include "service_rshell.h"
#include "service_rsync.h"
#include "service_rtmp.h"
-#include "service_smtp.h"
#include "service_snmp.h"
#include "service_ssh.h"
#include "service_ssl.h"
static int CServiceAddPort(const RNAServiceValidationPort*, RNAServiceValidationModule*);
static void CServiceRemovePorts(RNAServiceValidationFCN validate);
-static IniServiceAPI svc_init_api =
+static InitServiceAPI svc_init_api =
{
&CServiceRegisterPattern,
&CServiceAddPort,
&rshell_service_mod,
&rsync_service_mod,
&rtmp_service_mod,
- &smtp_service_mod,
&snmp_service_mod,
&ssh_service_mod,
&ssl_service_mod,
uint32_t packetCount;
};
-static int battle_field_init(const IniServiceAPI* const init_api);
+static int battle_field_init(const InitServiceAPI* const init_api);
static int battle_field_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_BATTLEFIELD, 0 }
};
-static int battle_field_init(const IniServiceAPI* const init_api)
+static int battle_field_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&battle_field_validate, IpProtocol::TCP, (uint8_t*)PATTERN_HELLO,
sizeof(PATTERN_HELLO)-1, 5, "battle_field");
#pragma pack()
-static int bgp_init(const IniServiceAPI* const init_api);
+static int bgp_init(const InitServiceAPI* const init_api);
static int bgp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_BGP, 0 }
};
-static int bgp_init(const IniServiceAPI* const init_api)
+static int bgp_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&bgp_validate, IpProtocol::TCP, BGP_PATTERN,
sizeof(BGP_PATTERN), 0, "bgp");
};
#pragma pack()
-static int bit_init(const IniServiceAPI* const init_api);
+static int bit_init(const InitServiceAPI* const init_api);
static int bit_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_BITTORRENT, 0 }
};
-static int bit_init(const IniServiceAPI* const init_api)
+static int bit_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&bit_validate, IpProtocol::TCP, (const uint8_t*)BIT_BANNER,
sizeof(BIT_BANNER)-1, 0, svc_name);
#pragma pack()
-static int bootp_init(const IniServiceAPI* const init_api);
+static int bootp_init(const InitServiceAPI* const init_api);
static int bootp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_DHCP, APPINFO_FLAG_SERVICE_ADDITIONAL | APPINFO_FLAG_SERVICE_UDP_REVERSED }
};
-static int bootp_init(const IniServiceAPI* const init_api)
+static int bootp_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
unsigned count;
};
-static int dcerpc_init(const IniServiceAPI* const init_api);
+static int dcerpc_init(const InitServiceAPI* const init_api);
static int dcerpc_tcp_validate(ServiceValidationArgs* args);
static int dcerpc_udp_validate(ServiceValidationArgs* args);
{ APP_ID_DCE_RPC, 0 }
};
-static int dcerpc_init(const IniServiceAPI* const init_api)
+static int dcerpc_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
uint32_t packetCount;
};
-static int direct_connect_init(const IniServiceAPI* const init_api);
+static int direct_connect_init(const InitServiceAPI* const init_api);
static int direct_connect_validate(ServiceValidationArgs* args);
static int validateDirectConnectTcp(const uint8_t* data, uint16_t size, const int dir,
AppIdSession* asd, const Packet* pkt, ServiceData* serviceData);
{ APP_ID_DIRECT_CONNECT, 0 }
};
-static int direct_connect_init(const IniServiceAPI* const init_api)
+static int direct_connect_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&direct_connect_validate, IpProtocol::TCP, (uint8_t*)PATTERN1,
sizeof(PATTERN1)-1, 0, "direct_connect");
#pragma pack()
-static int flap_init(const IniServiceAPI* const init_api);
+static int flap_init(const InitServiceAPI* const init_api);
static int flap_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_AOL_INSTANT_MESSENGER, 0 }
};
-static int flap_init(const IniServiceAPI* const init_api)
+static int flap_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&flap_validate, IpProtocol::TCP, FLAP_PATTERN,
sizeof(FLAP_PATTERN), 0, "flap");
#pragma pack()
-static int ftp_init(const IniServiceAPI* const init_api);
+static int ftp_init(const InitServiceAPI* const init_api);
static int ftp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
static int16_t ftp_data_app_id = 0;
-static int ftp_init(const IniServiceAPI* const init_api)
+static int ftp_init(const InitServiceAPI* const init_api)
{
ftp_data_app_id = add_appid_protocol_reference("ftp-data");
unsigned count;
};
-static int irc_init(const IniServiceAPI* const init_api);
+static int irc_init(const InitServiceAPI* const init_api);
static int irc_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_IRCD, 0 }
};
-static int irc_init(const IniServiceAPI* const init_api)
+static int irc_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
unsigned count;
};
-static int lpr_init(const IniServiceAPI* const init_api);
+static int lpr_init(const InitServiceAPI* const init_api);
static int lpr_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_PRINTSRV, 0 }
};
-static int lpr_init(const IniServiceAPI* const init_api)
+static int lpr_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
MatchedPatterns* patternList;
};
-static int MDNS_init(const IniServiceAPI* const init_api);
+static int MDNS_init(const InitServiceAPI* const init_api);
static int ReferencePointer(const char* start_ptr,const char** resp_endptr, int* start_index,
uint16_t data_size, uint8_t* user_name_len, unsigned offset, const AppIdConfig* pConfig);
static int MDNS_validate(ServiceValidationArgs* args);
{ APP_ID_MDNS, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int MDNS_init(const IniServiceAPI* const init_api)
+static int MDNS_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
#pragma pack()
-static int svc_mysql_init(const IniServiceAPI* const init_api);
+static int svc_mysql_init(const InitServiceAPI* const init_api);
static int svc_mysql_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element
{ APP_ID_MYSQL, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int svc_mysql_init(const IniServiceAPI* const init_api)
+static int svc_mysql_init(const InitServiceAPI* const init_api)
{
for ( unsigned i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++ )
{
#pragma pack()
-static int netbios_init(const IniServiceAPI* const init_api);
+static int netbios_init(const InitServiceAPI* const init_api);
static int nbns_validate(ServiceValidationArgs* args);
static int nbss_validate(ServiceValidationArgs* args);
static int nbdgm_validate(ServiceValidationArgs* args);
0
};
-static int netbios_init(const IniServiceAPI* const init_api)
+static int netbios_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&nbss_validate, IpProtocol::TCP, NB_SMB_BANNER,
sizeof(NB_SMB_BANNER), -1, "netbios");
#pragma pack()
-static int nntp_init(const IniServiceAPI* const init_api);
+static int nntp_init(const InitServiceAPI* const init_api);
static int nntp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_NNTP, 0 }
};
-static int nntp_init(const IniServiceAPI* const init_api)
+static int nntp_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&nntp_validate, IpProtocol::TCP, (uint8_t*)NNTP_PATTERN1,
sizeof(NNTP_PATTERN1)-1, 0, "nntp");
#pragma pack()
-static int ntp_init(const IniServiceAPI* const init_api);
+static int ntp_init(const InitServiceAPI* const init_api);
static int ntp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_NTP, 0 }
};
-static int ntp_init(const IniServiceAPI* const init_api)
+static int ntp_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
#pragma pack()
-static int radius_init(const IniServiceAPI* const init_api);
+static int radius_init(const InitServiceAPI* const init_api);
static int radius_validate(ServiceValidationArgs* args);
static int radius_validate_accounting(ServiceValidationArgs* args);
{ APP_ID_RADIUS, APPINFO_FLAG_SERVICE_UDP_REVERSED }
};
-static int radius_init(const IniServiceAPI* const init_api)
+static int radius_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
struct ServiceREXECData* child;
};
-static int rexec_init(const IniServiceAPI* const init_api);
+static int rexec_init(const InitServiceAPI* const init_api);
static int rexec_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
static int16_t app_id = 0;
-static int rexec_init(const IniServiceAPI* const init_api)
+static int rexec_init(const InitServiceAPI* const init_api)
{
unsigned i;
#define RFB_BANNER "RFB "
-static int rfb_init(const IniServiceAPI* const init_api);
+static int rfb_init(const InitServiceAPI* const init_api);
static int rfb_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_VNC_RFB, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int rfb_init(const IniServiceAPI* const init_api)
+static int rfb_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&rfb_validate, IpProtocol::TCP, (uint8_t*)RFB_BANNER,
sizeof(RFB_BANNER) - 1, 0, "rfb");
RLOGINState state;
};
-static int rlogin_init(const IniServiceAPI* const init_api);
+static int rlogin_init(const InitServiceAPI* const init_api);
static int rlogin_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_RLOGIN, 0 }
};
-static int rlogin_init(const IniServiceAPI* const init_api)
+static int rlogin_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
int once;
};
-static int rpc_init(const IniServiceAPI* const init_api);
+static int rpc_init(const InitServiceAPI* const init_api);
static int rpc_validate(ServiceValidationArgs* args);
static int rpc_tcp_validate(ServiceValidationArgs* args);
static int16_t app_id = 0;
-static int rpc_init(const IniServiceAPI* const init_api)
+static int rpc_init(const InitServiceAPI* const init_api)
{
struct rpcent* rpc;
RPCProgram* prog;
ServiceRSHELLData* child;
};
-static int rshell_init(const IniServiceAPI* const init_api);
+static int rshell_init(const InitServiceAPI* const init_api);
static int rshell_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
static int16_t app_id = 0;
-static int rshell_init(const IniServiceAPI* const init_api)
+static int rshell_init(const InitServiceAPI* const init_api)
{
unsigned i;
}
pf->scan_flags |= SCAN_HOST_PORT_FLAG;
PopulateExpectedFlow(asd, pf,
+ APPID_SESSION_CONTINUE |
+ APPID_SESSION_REXEC_STDERR |
APPID_SESSION_NO_TPI |
- APPID_SESSION_IGNORE_HOST |
+ APPID_SESSION_SERVICE_DETECTED |
APPID_SESSION_NOT_A_SERVICE |
APPID_SESSION_PORT_SERVICE_DONE);
pf->rnaServiceState = RNA_STATE_STATEFUL;
RSYNCState state;
};
-static int rsync_init(const IniServiceAPI* const init_api);
+static int rsync_init(const InitServiceAPI* const init_api);
static int rsync_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_RSYNC, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int rsync_init(const IniServiceAPI* const init_api)
+static int rsync_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&rsync_validate, IpProtocol::TCP, (uint8_t*)RSYNC_BANNER,
sizeof(RSYNC_BANNER)-1, 0, "rsync");
char* pageUrl;
};
-static int rtmp_init(const IniServiceAPI* const api);
+static int rtmp_init(const InitServiceAPI* const api);
static int rtmp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_RTMP, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int rtmp_init(const IniServiceAPI* const init_api)
+static int rtmp_init(const InitServiceAPI* const init_api)
{
unsigned i;
for (i = 0; i < (sizeof(appIdRegistry) / sizeof(*appIdRegistry)); i++)
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// service_smtp.cc author Sourcefire Inc.
-
-#include "service_smtp.h"
-
-#include "main/snort_debug.h"
-#include "utils/util.h"
-
-#include "service_util.h"
-#include "application_ids.h"
-#include "service_api.h"
-#include "appid_module.h"
-
-#define SMTP_PORT 25
-#define SMTP_CLOSING_CONN "closing connection\x0d\x0a"
-
-enum SMTPState
-{
- SMTP_STATE_CONNECTION,
- SMTP_STATE_HELO,
- SMTP_STATE_TRANSFER,
- SMTP_STATE_CONNECTION_ERROR,
- SMTP_STATE_STARTTLS
-};
-
-struct ServiceSMTPData
-{
- SMTPState state;
- int code;
- int multiline;
- int set_flags;
-};
-
-#pragma pack(1)
-
-struct ServiceSMTPCode
-{
- uint8_t code[3];
- uint8_t sp;
-};
-
-#pragma pack()
-
-static int smtp_init(const IniServiceAPI* const init_api);
-static int smtp_validate(ServiceValidationArgs* args);
-
-static const RNAServiceElement svc_element =
-{
- nullptr,
- &smtp_validate,
- nullptr,
- DETECTOR_TYPE_DECODER,
- 1,
- 1,
- 0,
- "smtp"
-};
-
-static const RNAServiceValidationPort pp[] =
-{
- { &smtp_validate, 25, IpProtocol::TCP, 0 },
- { nullptr, 0, IpProtocol::PROTO_NOT_SET, 0 }
-};
-
-RNAServiceValidationModule smtp_service_mod =
-{
- "SMTP",
- &smtp_init,
- pp,
- nullptr,
- nullptr,
- 0,
- nullptr,
- 0
-};
-
-static AppRegistryEntry appIdRegistry[] =
-{
- { APP_ID_SMTP, 0 },
- { APP_ID_SMTPS, 0 }
-};
-
-static int smtp_init(const IniServiceAPI* const init_api)
-{
- const char SMTP_PATTERN1[] = "220 ";
- const char SMTP_PATTERN2[] = "220-";
- const char SMTP_PATTERN3[] = "SMTP";
- const char SMTP_PATTERN4[] = "smtp";
-
- init_api->RegisterPattern(&smtp_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN1,
- sizeof(SMTP_PATTERN1) - 1, 0, "smtp");
- init_api->RegisterPattern(&smtp_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN2,
- sizeof(SMTP_PATTERN2) - 1, 0, "smtp");
- init_api->RegisterPattern(&smtp_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN3,
- sizeof(SMTP_PATTERN3) - 1, -1, "smtp");
- init_api->RegisterPattern(&smtp_validate, IpProtocol::TCP, (uint8_t*)SMTP_PATTERN4,
- sizeof(SMTP_PATTERN4) - 1, -1, "smtp");
-
- unsigned i;
- for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
- {
- DebugFormat(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
- init_api->RegisterAppId(&smtp_validate, appIdRegistry[i].appId,
- appIdRegistry[i].additionalInfo);
- }
-
- return 0;
-}
-
-static int smtp_validate_reply(const uint8_t* data, uint16_t* offset,
- uint16_t size, int* multi, int* code)
-{
- const ServiceSMTPCode* code_hdr;
- int tmp;
-
- /* Trim any blank lines (be a little tolerant) */
- for (; *offset<size; (*offset)++)
- {
- if (data[*offset] != 0x0D && data[*offset] != 0x0A)
- break;
- }
-
- if (size - *offset < (int)sizeof(ServiceSMTPCode))
- {
- for (; *offset<size; (*offset)++)
- {
- if (!isspace(data[*offset]))
- return -1;
- }
- return 0;
- }
-
- code_hdr = (ServiceSMTPCode*)(data + *offset);
-
- if (code_hdr->code[0] < '1' || code_hdr->code[0] > '5')
- return -1;
- tmp = (code_hdr->code[0] - '0') * 100;
-
- if (code_hdr->code[1] < '0' || code_hdr->code[1] > '5')
- return -1;
- tmp += (code_hdr->code[1] - '0') * 10;
-
- if (!isdigit(code_hdr->code[2]))
- return -1;
- tmp += code_hdr->code[2] - '0';
-
- if (*multi && tmp != *code)
- return -1;
- *code = tmp;
- if (code_hdr->sp == '-')
- *multi = 1;
- else if (code_hdr->sp == ' ')
- *multi = 0;
- else
- return -1;
-
- /* We have a valid code, now we need to see if the rest of the line
- is okay */
-
- *offset += sizeof(ServiceSMTPCode);
- for (; *offset < size; (*offset)++)
- {
- if (data[*offset] == 0x0D)
- {
- (*offset)++;
- if (*offset >= size)
- return -1;
- if (data[*offset] != 0x0A)
- return -1;
- }
- if (data[*offset] == 0x0A)
- {
- if (*multi)
- {
- if ((*offset + 1) >= size)
- return 0;
-
- if (size - (*offset + 1) < (int)sizeof(ServiceSMTPCode))
- return -1;
-
- code_hdr = (ServiceSMTPCode*)(data + *offset + 1);
-
- if (code_hdr->code[0] < '1' || code_hdr->code[0] > '5')
- return -1;
- tmp = (code_hdr->code[0] - '0') * 100;
-
- if (code_hdr->code[1] < '1' || code_hdr->code[1] > '5')
- return -1;
- tmp += (code_hdr->code[1] - '0') * 10;
-
- if (!isdigit(code_hdr->code[2]))
- return -1;
- tmp += code_hdr->code[2] - '0';
-
- if (tmp != *code)
- return -1;
-
- if (code_hdr->sp == ' ')
- *multi = 0;
- else if (code_hdr->sp != '-')
- return -1;
-
- *offset += sizeof(ServiceSMTPCode);
- }
- else
- {
- (*offset)++;
- return *code;
- }
- }
- else if (!isprint(data[*offset]))
- return -1;
- }
-
- return 0;
-}
-
-static int smtp_validate(ServiceValidationArgs* args)
-{
- ServiceSMTPData* fd;
- AppIdSession* asd = args->asd;
- const uint8_t* data = args->data;
- uint16_t size = args->size;
- uint16_t offset;
-
- if (!size)
- goto inprocess;
- if (args->dir != APP_ID_FROM_RESPONDER)
- goto inprocess;
-
- fd = (ServiceSMTPData*)smtp_service_mod.api->data_get(asd, smtp_service_mod.flow_data_index);
- if (!fd)
- {
- fd = (ServiceSMTPData*)snort_calloc(sizeof(ServiceSMTPData));
- smtp_service_mod.api->data_add(asd, fd, smtp_service_mod.flow_data_index, &snort_free);
- fd->state = SMTP_STATE_CONNECTION;
- }
- else
- {
- if (asd->get_session_flags(APPID_SESSION_ENCRYPTED) && fd->state == SMTP_STATE_TRANSFER)
- {
- fd->state = SMTP_STATE_STARTTLS;
- }
- }
-
- if (!fd->set_flags)
- {
- fd->set_flags = 1;
- asd->set_session_flags(APPID_SESSION_CLIENT_GETS_SERVER_PACKETS);
- }
-
- offset = 0;
- while (offset < size)
- {
- if (smtp_validate_reply(data, &offset, size, &fd->multiline, &fd->code) < 0)
- goto fail;
- if (!fd->code)
- goto inprocess;
- switch (fd->state)
- {
- case SMTP_STATE_CONNECTION:
- switch (fd->code)
- {
- case 220:
- fd->state = SMTP_STATE_HELO;
- break;
- case 421:
- if (service_strstr(data, size, (const uint8_t*)SMTP_CLOSING_CONN,
- sizeof(SMTP_CLOSING_CONN)-1))
- goto success;
- case 520:
- fd->state = SMTP_STATE_CONNECTION_ERROR;
- break;
- default:
- goto fail;
- }
- break;
- case SMTP_STATE_HELO:
- switch (fd->code)
- {
- case 250:
- fd->state = SMTP_STATE_TRANSFER;
- break;
- case 500:
- case 501:
- case 504:
- break;
- case 421:
- case 553:
- fd->state = SMTP_STATE_CONNECTION_ERROR;
- break;
- default:
- goto fail;
- }
- break;
- case SMTP_STATE_STARTTLS:
- if (fd->code == 220)
- goto success;
- /* STARTTLS failed. */
- asd->clear_session_flags(APPID_SESSION_ENCRYPTED); // not encrypted after all
- fd->state = SMTP_STATE_HELO; // revert the state
- break;
- case SMTP_STATE_TRANSFER:
- goto success;
- case SMTP_STATE_CONNECTION_ERROR:
- default:
- goto fail;
- }
- }
-
-inprocess:
- smtp_service_mod.api->service_inprocess(asd, args->pkt, args->dir, &svc_element);
- return SERVICE_INPROCESS;
-
-success:
- smtp_service_mod.api->add_service(asd, args->pkt, args->dir, &svc_element,
- fd->state == SMTP_STATE_STARTTLS ? APP_ID_SMTPS : APP_ID_SMTP,
- nullptr, nullptr, nullptr);
- if (fd->state == SMTP_STATE_STARTTLS)
- appid_stats.smtps_flows++;
- else
- appid_stats.smtp_flows++;
-
- return SERVICE_SUCCESS;
-
-fail:
- smtp_service_mod.api->fail_service(asd, args->pkt, args->dir, &svc_element,
- smtp_service_mod.flow_data_index);
- return SERVICE_NOMATCH;
-}
-
#pragma pack()
-static int snmp_init(const IniServiceAPI* const init_api);
+static int snmp_init(const InitServiceAPI* const init_api);
static int snmp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
static int16_t app_id = 0;
-static int snmp_init(const IniServiceAPI* const init_api)
+static int snmp_init(const InitServiceAPI* const init_api)
{
app_id = add_appid_protocol_reference("snmp");
#pragma pack()
-static int ssh_init(const IniServiceAPI* const init_api);
+static int ssh_init(const InitServiceAPI* const init_api);
static int ssh_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_SSH, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int ssh_init(const IniServiceAPI* const init_api)
+static int ssh_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&ssh_validate, IpProtocol::TCP, (uint8_t*)SSH_BANNER,
sizeof(SSH_BANNER) - 1, 0, "ssh");
return retVal;
}
-static int ssl_init(const IniServiceAPI* const api);
+static int ssl_init(const InitServiceAPI* const api);
static int ssl_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_SSL, APPINFO_FLAG_SERVICE_ADDITIONAL }
};
-static int ssl_init(const IniServiceAPI* const init_api)
+static int ssl_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&ssl_validate, IpProtocol::TCP, SSL_PATTERN_PCT,
sizeof(SSL_PATTERN_PCT), 2, "ssl");
unsigned count;
};
-static int telnet_init(const IniServiceAPI* const init_api);
+static int telnet_init(const InitServiceAPI* const init_api);
static int telnet_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_TELNET, 0 }
};
-static int telnet_init(const IniServiceAPI* const init_api)
+static int telnet_init(const InitServiceAPI* const init_api)
{
for (unsigned i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
{
#pragma pack()
-static int tftp_init(const IniServiceAPI* const api);
+static int tftp_init(const InitServiceAPI* const api);
static int tftp_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
static int16_t app_id = 0;
-static int tftp_init(const IniServiceAPI* const init_api)
+static int tftp_init(const InitServiceAPI* const init_api)
{
app_id = add_appid_protocol_reference("tftp");
};
#pragma pack()
-static int timbuktu_init(const IniServiceAPI* const init_api);
+static int timbuktu_init(const InitServiceAPI* const init_api);
static int timbuktu_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_TIMBUKTU, 0 }
};
-static int timbuktu_init(const IniServiceAPI* const init_api)
+static int timbuktu_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&timbuktu_validate, IpProtocol::TCP,
(const uint8_t*)TIMBUKTU_BANNER, sizeof(TIMBUKTU_BANNER) - 1,
};
#pragma pack()
-static int tns_init(const IniServiceAPI* const init_api);
+static int tns_init(const InitServiceAPI* const init_api);
static int tns_validate(ServiceValidationArgs* args);
static const RNAServiceElement svc_element =
{ APP_ID_ORACLE_TNS, APPINFO_FLAG_SERVICE_ADDITIONAL },
};
-static int tns_init(const IniServiceAPI* const init_api)
+static int tns_init(const InitServiceAPI* const init_api)
{
init_api->RegisterPattern(&tns_validate, IpProtocol::TCP, (const uint8_t*)TNS_BANNER,
TNS_BANNER_LEN, 2, svc_name);
void Flow::set_application_ids(AppId, AppId, AppId, AppId) { }
const char *content_type = nullptr;
+const char *cookie = nullptr;
const char *host = nullptr;
+const char *location = nullptr;
const char *referer = nullptr;
int32_t response_code = 0;
const char *server = nullptr;
const char *x_working_with = nullptr;
-const char *url = nullptr;
+const char *uri = nullptr;
const char *useragent = nullptr;
const char *via = nullptr;
global_field.set(strlen(host), (const uint8_t*)host);
}
+ if(sub_id == HttpEnums::HEAD_COOKIE)
+ {
+ if(cookie)
+ global_field.set(strlen(cookie), (const uint8_t*)cookie);
+ }
+
if(sub_id == HttpEnums::HEAD_USER_AGENT)
{
if(useragent)
if(content_type)
global_field.set(strlen(content_type), (const uint8_t*)content_type);
}
+
+ if(sub_id == HttpEnums::HEAD_LOCATION)
+ {
+ if(location)
+ global_field.set(strlen(location), (const uint8_t*)location);
+ }
}
if(id == HttpEnums::HTTP_BUFFER_URI)
{
if(sub_id == 0)
{
- if(url)
- global_field.set(strlen(url), (const uint8_t*)url);
+ if(uri)
+ global_field.set(strlen(uri), (const uint8_t*)uri);
}
}
AppIdSession *fake_session = nullptr;
FakeHttpMsgHeader *fake_msg_header = nullptr;
-AppIdSession::AppIdSession(IpProtocol, const sfip_t*) : FlowData(flow_id, nullptr)
+AppIdSession::AppIdSession(IpProtocol, const sfip_t*, uint16_t) : FlowData(flow_id, nullptr)
{
}
if(!hsession)
return;
- if(hsession->content_type) free(hsession->content_type);
- if(hsession->host) free(hsession->host);
- if(hsession->referer) free(hsession->referer);
- if(hsession->response_code) free(hsession->response_code);
- if(hsession->server) free(hsession->server);
- if(hsession->url) free(hsession->url);
- if(hsession->useragent) free(hsession->useragent);
- if(hsession->via) free(hsession->via);
- if(hsession->x_working_with) free(hsession->x_working_with);
+ if(hsession->content_type)
+ free(hsession->content_type);
+ if(hsession->cookie)
+ free(hsession->cookie);
+ if(hsession->host)
+ free(hsession->host);
+ if(hsession->location)
+ free(hsession->location);
+ if(hsession->referer)
+ free(hsession->referer);
+ if(hsession->response_code)
+ free(hsession->response_code);
+ if(hsession->server)
+ free(hsession->server);
+ if(hsession->uri)
+ free(hsession->uri);
+ if(hsession->url)
+ snort_free(hsession->url);
+ if(hsession->useragent)
+ free(hsession->useragent);
+ if(hsession->via)
+ free(hsession->via);
+ if(hsession->x_working_with)
+ free(hsession->x_working_with);
+
snort_free(hsession);
}
return fake_session;
}
-const uint8_t* HttpEvent::get_content_type(unsigned &length)
+const uint8_t* HttpEvent::get_content_type(int32_t &length)
{
global_field.set(0, nullptr);
if(content_type)
return global_field.start;
}
-const uint8_t* HttpEvent::get_host(unsigned &length)
+const uint8_t* HttpEvent::get_cookie(int32_t &length)
+{
+ global_field.set(0, nullptr);
+ if(cookie)
+ global_field.set(strlen(cookie), (const uint8_t*)cookie);
+ length = global_field.length;
+ return global_field.start;
+}
+
+const uint8_t* HttpEvent::get_host(int32_t &length)
{
global_field.set(0, nullptr);
if(host)
return global_field.start;
}
-const uint8_t* HttpEvent::get_referer(unsigned &length)
+const uint8_t* HttpEvent::get_location(int32_t &length)
+{
+ global_field.set(0, nullptr);
+ if(location)
+ global_field.set(strlen(location), (const uint8_t*)location);
+ length = global_field.length;
+ return global_field.start;
+}
+
+const uint8_t* HttpEvent::get_referer(int32_t &length)
{
global_field.set(0, nullptr);
if(referer)
return response_code;
}
-const uint8_t* HttpEvent::get_server(unsigned &length)
+const uint8_t* HttpEvent::get_server(int32_t &length)
{
global_field.set(0, nullptr);
if(server)
return global_field.start;
}
-const uint8_t* HttpEvent::get_uri(unsigned &length)
+const uint8_t* HttpEvent::get_uri(int32_t &length)
{
global_field.set(0, nullptr);
- if(url)
- global_field.set(strlen(url), (const uint8_t*)url);
+ if(uri)
+ global_field.set(strlen(uri), (const uint8_t*)uri);
length = global_field.length;
return global_field.start;
}
-const uint8_t* HttpEvent::get_user_agent(unsigned &length)
+const uint8_t* HttpEvent::get_user_agent(int32_t &length)
{
global_field.set(0, nullptr);
if(useragent)
return global_field.start;
}
-const uint8_t* HttpEvent::get_via(unsigned &length)
+const uint8_t* HttpEvent::get_via(int32_t &length)
{
global_field.set(0, nullptr);
if(via)
return global_field.start;
}
-const uint8_t* HttpEvent::get_x_working_with(unsigned &length)
+const uint8_t* HttpEvent::get_x_working_with(int32_t &length)
{
global_field.set(0, nullptr);
if(x_working_with)
{
FakeFlow flow;
HttpEvent event(nullptr);
- AppIdSession session(IpProtocol::TCP, nullptr);
+ AppIdSession session(IpProtocol::TCP, nullptr, 1492);
HttpEventHandler event_handler(HttpEventHandler::REQUEST_EVENT);
fake_session = &session;
}
#define CONTENT_TYPE "html/text"
+#define COOKIE "this is my request cookie content"
#define HOST "www.google.com"
-#define URL "http://www.google.com/path/to/index.html"
+#define LOCATION "abc.yahoo.com"
+#define URI "/path/to/index.html"
#define USERAGENT "Mozilla/5.0 (Macintosh; Intel Mac OS X)"
#define REFERER "http://www.yahoo.com/search"
#define RESPONSE_CODE 301
unsigned scan_flags = 0;
PegCount http_flows = 1; // Default to 1 since most tests have 1.
const char *content_type = nullptr;
+ const char *cookie = nullptr;
const char *host = nullptr;
+ const char *location = nullptr;
const char *referer = nullptr;
int32_t response_code = 0;
const char *server = nullptr;
const char *x_working_with = nullptr;
- const char *url = nullptr;
+ const char *uri = nullptr;
const char *useragent = nullptr;
const char *via = nullptr;
};
{
FakeFlow flow;
HttpEvent event(nullptr);
- AppIdSession session(IpProtocol::TCP, nullptr);
+ AppIdSession session(IpProtocol::TCP, nullptr, 1492);
FakeHttpMsgHeader http_msg_header;
HttpEventHandler event_handler(test_data.type);
fake_session = &session;
fake_msg_header = &http_msg_header;
host = test_data.host;
+ location = test_data.location;
referer = test_data.referer;
server = test_data.server;
x_working_with = test_data.x_working_with;
- url = test_data.url;
+ uri = test_data.uri;
useragent = test_data.useragent;
via = test_data.via;
content_type = test_data.content_type;
+ cookie = test_data.cookie;
response_code = test_data.response_code;
if(expect_data == nullptr)
LONGS_EQUAL(expect_data->scan_flags, session.scan_flags);
LONGS_EQUAL(expect_data->http_flows, appid_stats.http_flows);
STRCMP_EQUAL(expect_data->host, session.hsession->host);
- STRCMP_EQUAL(expect_data->url, session.hsession->url);
+ STRCMP_EQUAL(expect_data->uri, session.hsession->uri);
STRCMP_EQUAL(expect_data->content_type, session.hsession->content_type);
+ STRCMP_EQUAL(expect_data->cookie, session.hsession->cookie);
+ STRCMP_EQUAL(expect_data->location, session.hsession->location);
STRCMP_EQUAL(expect_data->referer, session.hsession->referer);
STRCMP_EQUAL(expect_data->server, session.hsession->server);
STRCMP_EQUAL(expect_data->x_working_with, session.hsession->x_working_with);
run_event_handler(test_data);
}
-TEST(appid_http_event, handle_msg_header_host_and_url)
+TEST(appid_http_event, handle_msg_header_cookie)
+{
+ TestData test_data;
+ test_data.scan_flags = 0;
+ test_data.cookie = COOKIE;
+
+ run_event_handler(test_data);
+}
+
+TEST(appid_http_event, handle_msg_header_host_and_uri)
{
TestData test_data;
test_data.scan_flags = SCAN_HTTP_HOST_URL_FLAG;
test_data.host = HOST;
- test_data.url = URL;
+ test_data.uri = URI;
run_event_handler(test_data);
}
run_event_handler(test_data);
}
+TEST(appid_http_event, handle_msg_header_location)
+{
+ TestData test_data;
+ test_data.type = HttpEventHandler::RESPONSE_EVENT;
+ test_data.scan_flags = 0;
+ test_data.http_flows = 0; // Flows are only counted on request header
+ test_data.location = LOCATION;
+
+ run_event_handler(test_data);
+}
+
TEST(appid_http_event, handle_msg_header_server)
{
TestData test_data;
test_data.http_flows = 0; // Flows are only counted on request header
test_data.response_code = RESPONSE_CODE;
test_data.content_type = CONTENT_TYPE;
+ test_data.location = LOCATION;
test_data.via = VIA;
TestData expect_data = test_data;
// Fill in the request data too to demonstrate that it is not copied
// during response header handling.
- test_data.url = URL;
+ test_data.uri = URI;
test_data.host = HOST;
test_data.referer = REFERER;
test_data.useragent = USERAGENT;
+ test_data.cookie = COOKIE;
run_event_handler(test_data, &expect_data);
}
test_data.type = HttpEventHandler::REQUEST_EVENT;
test_data.scan_flags = SCAN_HTTP_VIA_FLAG | SCAN_HTTP_USER_AGENT_FLAG |
SCAN_HTTP_HOST_URL_FLAG;
- test_data.url = URL;
+ test_data.uri = URI;
+ test_data.cookie = COOKIE;
test_data.host = HOST;
test_data.referer = REFERER;
test_data.useragent = USERAGENT;
// during response header handling.
test_data.response_code = RESPONSE_CODE;
test_data.content_type = CONTENT_TYPE;
+ test_data.location = LOCATION;
run_event_handler(test_data, &expect_data);
}
{
char* spdyRequestPath;
char* spdyRequestScheme;
- char* spdyRequesHost;
- char* httpRequesUrl;
+ char* spdyRequestHost;
+ char* httpRequestUrl;
char* httpRequestUri;
+ uint16_t httpRequestUriLen;
uint16_t httpRequestUriOffset;
uint16_t httpRequestUriEndOffset;
- char* httpRequesHost;
- char* httpRequestCookie;
+ char *httpRequestHost;
+ uint16_t httpRequestHostLen;
+ char *httpRequestCookie;
+ uint16_t httpRequestCookieLen;
uint16_t httpRequestCookieOffset;
uint16_t httpRequestCookieEndOffset;
- char* httpRequestVia;
- char* httpResponseVia;
- char* httpResponseUpgrade;
- char* httpRequestUserAgent;
- char* httpResponseVersion;
- char* httpResponseCode;
- char* httpResponseContent;
- char* httpResponseLocation;
- char* httpResponseBody;
- char* httpRequestBody;
- char* httpResponseServer;
- char* httpRequestXWorkingWith;
- char* tlsHost;
- char* tlsCname;
- char* tlsOrgUnit;
- char* httpRequestReferer;
- char* ftpCommandUser;
- XffFieldValue xffFieldValue[HTTP_MAX_XFF_FIELDS];
+ char *httpRequestVia;
+ char *httpResponseVia;
+ char *httpResponseUpgrade;
+ char *httpRequestUserAgent;
+ uint16_t httpRequestUserAgentLen;
+ char *httpResponseVersion;
+ char *httpResponseCode;
+ uint16_t httpResponseCodeLen;
+ char *httpResponseContent;
+ uint16_t httpResponseContentLen;
+ char *httpResponseLocation;
+ uint16_t httpResponseLocationLen;
+ char *httpResponseBody;
+ uint16_t httpResponseBodyLen;
+ char *httpRequestBody;
+ uint16_t httpRequestBodyLen;
+ char *httpResponseServer;
+ char *httpRequestXWorkingWith;
+ char *tlsHost;
+ char *tlsCname;
+ char *tlsOrgUnit;
+ char *httpRequestReferer;
+ uint16_t httpRequestRefererLen;
+ char *ftpCommandUser;
+ struct XffFieldValue xffFieldValue[HTTP_MAX_XFF_FIELDS];
uint8_t numXffFields;
+ uint16_t httpRequestUserAgentOffset;
+ uint16_t httpRequestUserAgentEndOffset;
+ uint16_t httpRequestHostOffset;
+ uint16_t httpRequestHostEndOffset;
+ uint16_t httpRequestRefererOffset;
+ uint16_t httpRequestRefererEndOffset;
+ uint16_t spdyRequestHostOffset;
+ uint16_t spdyRequestHostEndOffset;
+ uint16_t spdyRequestPathOffset;
+ uint16_t spdyRequestPathEndOffset;
};
#endif
#include "http_events.h"
#include "service_inspectors/http_inspect/http_msg_header.h"
-const uint8_t* HttpEvent::get_header(unsigned id, uint64_t sub_id, unsigned& length)
+const uint8_t* HttpEvent::get_header(unsigned id, uint64_t sub_id, int32_t& length)
{
Field field;
field = http_msg_header->get_classic_buffer(id, sub_id, 0);
}
}
-const uint8_t* HttpEvent::get_content_type(unsigned& length)
+const uint8_t* HttpEvent::get_content_type(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER,
HttpEnums::HEAD_CONTENT_TYPE, length);
}
-const uint8_t* HttpEvent::get_host(unsigned& length)
+const uint8_t* HttpEvent::get_cookie(int32_t& length)
+{
+ return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_COOKIE,
+ length);
+}
+
+const uint8_t* HttpEvent::get_host(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_HOST,
length);
}
-const uint8_t* HttpEvent::get_referer(unsigned& length)
+const uint8_t* HttpEvent::get_location(int32_t& length)
+{
+ return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_LOCATION,
+ length);
+}
+
+const uint8_t* HttpEvent::get_referer(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_REFERER,
length);
return http_msg_header->get_status_code();
}
-const uint8_t* HttpEvent::get_server(unsigned& length)
+const uint8_t* HttpEvent::get_server(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_SERVER,
length);
}
-const uint8_t* HttpEvent::get_uri(unsigned& length)
+const uint8_t* HttpEvent::get_uri(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_URI, 0, length);
}
-const uint8_t* HttpEvent::get_user_agent(unsigned& length)
+const uint8_t* HttpEvent::get_user_agent(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_USER_AGENT,
length);
}
-const uint8_t* HttpEvent::get_via(unsigned& length)
+const uint8_t* HttpEvent::get_via(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER, HttpEnums::HEAD_VIA,
length);
}
-const uint8_t* HttpEvent::get_x_working_with(unsigned& length)
+const uint8_t* HttpEvent::get_x_working_with(int32_t& length)
{
return get_header(HttpEnums::HTTP_BUFFER_HEADER,
HttpEnums::HEAD_X_WORKING_WITH, length);
{
}
- const uint8_t* get_content_type(unsigned &length);
- const uint8_t* get_host(unsigned &length);
- const uint8_t* get_referer(unsigned &length);
- const uint8_t* get_server(unsigned &length);
- const uint8_t* get_uri(unsigned &length);
- const uint8_t* get_user_agent(unsigned &length);
- const uint8_t* get_via(unsigned &length);
- const uint8_t* get_x_working_with(unsigned &length);
+ const uint8_t* get_content_type(int32_t &length);
+ const uint8_t* get_cookie(int32_t &length);
+ const uint8_t* get_host(int32_t &length);
+ const uint8_t* get_location(int32_t &length);
+ const uint8_t* get_referer(int32_t &length);
+ const uint8_t* get_server(int32_t &length);
+ const uint8_t* get_uri(int32_t &length);
+ const uint8_t* get_user_agent(int32_t &length);
+ const uint8_t* get_via(int32_t &length);
+ const uint8_t* get_x_working_with(int32_t &length);
int32_t get_response_code();
private:
HttpMsgHeader* const http_msg_header;
- const uint8_t* get_header(unsigned, uint64_t, unsigned&);
+ const uint8_t* get_header(unsigned, uint64_t, int32_t&);
};