From: Hui Cao (huica) Date: Thu, 27 Oct 2016 16:27:53 +0000 (-0400) Subject: Merge pull request #684 in SNORT/snort3 from appid_port2x_deltas to master X-Git-Tag: 3.0.0-233~208 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a6375b517313ebe251d20bd06cfdee4016045a7;p=thirdparty%2Fsnort3.git Merge pull request #684 in SNORT/snort3 from appid_port2x_deltas to master Squashed commit of the following: commit f0cfd6beb8a5fdc2a9f97e997eed31ee5eb8e08e Author: davis mcpherson Date: Wed Oct 26 16:26:38 2016 -0400 use 'free' to free hsession ptrs commit b7fa07525538c46fff16c2f3ba97bc9f6ffe8216 Author: davis mcpherson Date: Wed Oct 26 14:29:28 2016 -0400 patch to support initializing appid http header ptrs and lengths via pub/sub interface with nhttp inspector commit a007538457b691e3644eecc389755b65a0d06de9 Author: davis mcpherson Date: Mon Oct 24 08:15:04 2016 -0400 move stmp detector tests for clients from client_plugins dir to detector_plugins dir commit 1915d11be99da837f6703a7574d696f8753032d5 Author: davis mcpherson Date: Fri Oct 21 17:09:49 2016 -0400 port changes for lua detector chp http pattern management commit aaaa8490e52a7c5537a5034dce9ac23f7206d6f5 Author: davis mcpherson Date: Fri Oct 21 12:50:28 2016 -0400 port appid 2.x changes that converted smtp to detector model from separate client/service plugins removed deprecated client/service source files for smtp detectors commit c76a8ec0d2911841b3f00801e038486ce3d06319 Author: davis mcpherson Date: Thu Oct 20 16:21:37 2016 -0400 port of appid deltas from 2.x to the third party module support code commit 34886ef8ed672dfc43f7c4d4a72a1f8af007185b Author: davis mcpherson Date: Thu Oct 20 12:06:42 2016 -0400 port 2.x changes to logic that syncs ids used by appid and snort for various protocols commit 444e20cd2414b27ea1d0dd5a4283cb750b88e3c5 Author: davis mcpherson Date: Thu Oct 20 11:20:54 2016 -0400 port of appid changes since initial snapshot that are related to adding regex matching for http fields, application id updates, and changes to appid api methods --- diff --git a/configure.ac b/configure.ac index 83defd843..357c3882d 100644 --- a/configure.ac +++ b/configure.ac @@ -1147,7 +1147,7 @@ src/stream/file/Makefile \ 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 \ diff --git a/src/network_inspectors/appid/CMakeLists.txt b/src/network_inspectors/appid/CMakeLists.txt index 41bc93c01..8cd0159f2 100644 --- a/src/network_inspectors/appid/CMakeLists.txt +++ b/src/network_inspectors/appid/CMakeLists.txt @@ -14,8 +14,6 @@ set ( CP_APPID_SOURCES 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 @@ -76,8 +74,6 @@ set ( SP_APPID_SOURCES 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 @@ -108,6 +104,8 @@ set ( DP_APPID_SOURCES 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 ) @@ -200,7 +198,7 @@ set ( APPID_SOURCES 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} diff --git a/src/network_inspectors/appid/Makefile.am b/src/network_inspectors/appid/Makefile.am index 44f94fc85..1329d91c4 100644 --- a/src/network_inspectors/appid/Makefile.am +++ b/src/network_inspectors/appid/Makefile.am @@ -14,8 +14,6 @@ client_plugins/client_app_config.h \ 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 \ @@ -38,6 +36,8 @@ detector_plugins/detector_pattern.h \ 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 @@ -93,8 +93,6 @@ service_plugins/service_rsync.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 \ @@ -195,6 +193,6 @@ $(util_file_list) if ENABLE_UNIT_TESTS SUBDIRS=test\ service_plugins/test \ -client_plugins/test +detector_plugins/test endif diff --git a/src/network_inspectors/appid/appid_api.cc b/src/network_inspectors/appid/appid_api.cc index c7798a0b5..b4e7aefde 100644 --- a/src/network_inspectors/appid/appid_api.cc +++ b/src/network_inspectors/appid/appid_api.cc @@ -358,31 +358,45 @@ char* AppIdApi::get_http_request_body(AppIdSession* asd) 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) @@ -520,7 +534,7 @@ uint32_t AppIdApi::produce_ha_state(Flow* flow, uint8_t* buf) } 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) @@ -530,8 +544,9 @@ uint32_t AppIdApi::consume_ha_state(Flow* flow, const uint8_t* buf, uint8_t, IpP 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 | diff --git a/src/network_inspectors/appid/appid_api.h b/src/network_inspectors/appid/appid_api.h index ba2caa0e3..943b8612b 100644 --- a/src/network_inspectors/appid/appid_api.h +++ b/src/network_inspectors/appid/appid_api.h @@ -236,8 +236,8 @@ public: 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*); @@ -246,6 +246,8 @@ public: 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; diff --git a/src/network_inspectors/appid/appid_http_event_handler.cc b/src/network_inspectors/appid/appid_http_event_handler.cc index 0c6ef2313..bc14515c1 100644 --- a/src/network_inspectors/appid/appid_http_event_handler.cc +++ b/src/network_inspectors/appid/appid_http_event_handler.cc @@ -28,8 +28,8 @@ #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; @@ -39,14 +39,16 @@ static void replace_header_data(char **data, const uint8_t *header_start, 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); @@ -64,39 +66,68 @@ void HttpEventHandler::handle(DataEvent& event, Flow* 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(); @@ -109,15 +140,21 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow) { 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; } @@ -126,8 +163,8 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow) 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()); } diff --git a/src/network_inspectors/appid/appid_inspector.cc b/src/network_inspectors/appid/appid_inspector.cc index 27b914360..18ce2366c 100644 --- a/src/network_inspectors/appid/appid_inspector.cc +++ b/src/network_inspectors/appid/appid_inspector.cc @@ -87,8 +87,6 @@ bool AppIdInspector::configure(SnortConfig*) // 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... @@ -244,97 +242,6 @@ SO_PUBLIC const BaseApi* snort_plugins[] = 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. */ diff --git a/src/network_inspectors/appid/appid_session.cc b/src/network_inspectors/appid/appid_session.cc index 3f1b46b10..56a66c0ea 100644 --- a/src/network_inspectors/appid/appid_session.cc +++ b/src/network_inspectors/appid/appid_session.cc @@ -55,22 +55,15 @@ unsigned AppIdSession::flow_id = 0; 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"); } @@ -110,92 +103,34 @@ void AppIdSession::set_session_logging_state(const Packet* pkt, int direction) 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) @@ -239,7 +174,8 @@ AppIdSession* AppIdSession::create_future_session(const Packet* ctrlPkt, const s 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 @@ -403,7 +339,7 @@ bool AppIdSession::is_packet_ignored(Packet* p) // 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 @@ -423,15 +359,17 @@ bool AppIdSession::is_packet_ignored(Packet* p) { 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; @@ -443,6 +381,20 @@ bool AppIdSession::is_packet_ignored(Packet* p) 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) @@ -483,33 +435,8 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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"; @@ -533,48 +460,77 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, } 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://"; @@ -588,21 +544,21 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, //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; @@ -616,15 +572,14 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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) @@ -692,6 +647,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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). @@ -715,8 +671,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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, @@ -728,8 +683,16 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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) @@ -739,15 +702,16 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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) { @@ -758,6 +722,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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; } @@ -770,6 +735,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, hsession->chp_finished = 0; } hsession->location = attribute_data->httpResponseLocation; + hsession->location_buflen = attribute_data->httpResponseLocationLen; attribute_data->httpResponseLocation = nullptr; } if (attribute_data->httpRequestBody) @@ -784,6 +750,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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) @@ -795,6 +762,7 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, hsession->chp_finished = 0; } hsession->body = attribute_data->httpResponseBody; + hsession->body_buflen = attribute_data->httpResponseBodyLen; attribute_data->httpResponseBody = nullptr; } if (attribute_data->numXffFields) @@ -833,10 +801,10 @@ void AppIdSession::ProcessThirdPartyResults(Packet* p, int confidence, 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; } } @@ -979,19 +947,19 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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); @@ -999,16 +967,6 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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)) @@ -1024,6 +982,23 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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 { @@ -1034,11 +1009,13 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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)) { @@ -1046,6 +1023,7 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i // 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)) { @@ -1059,7 +1037,18 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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)) { @@ -1091,8 +1080,7 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i 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, @@ -1117,8 +1105,8 @@ bool AppIdSession::do_third_party_discovery(IpProtocol protocol, const sfip_t* i } 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) { @@ -1500,9 +1488,17 @@ void AppIdSession::do_application_discovery(Packet* p) { 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) @@ -1510,15 +1506,6 @@ void AppIdSession::do_application_discovery(Packet* p) 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); } @@ -1651,27 +1638,14 @@ void AppIdSession::do_application_discovery(Packet* p) 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 && @@ -1693,14 +1667,39 @@ void AppIdSession::do_application_discovery(Packet* p) 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. */ @@ -1740,6 +1739,7 @@ void AppIdSession::do_application_discovery(Packet* p) 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 @@ -2279,35 +2279,58 @@ void AppIdSession::set_client_app_id_data(AppId clientAppId, char** version) 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; + } } } } @@ -2591,14 +2614,15 @@ void AppIdSession::free_http_session_data() 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); @@ -3056,19 +3080,18 @@ void AppIdSession::clear_app_id_data() 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; @@ -3091,7 +3114,7 @@ int AppIdSession::initial_CHP_sweep(char** chp_buffers, MatchedCHPAction** ppmat { // 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]) { @@ -3106,7 +3129,7 @@ int AppIdSession::initial_CHP_sweep(char** chp_buffers, MatchedCHPAction** ppmat 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] + @@ -3164,7 +3187,7 @@ void AppIdSession::clearMiscHttpFlags() void AppIdSession::processCHP(char** version, Packet* p) { - int i, size; + int i; int found_in_buffer = 0; char* user = nullptr; AppId chp_final; @@ -3184,6 +3207,18 @@ void AppIdSession::processCHP(char** version, Packet* p) 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, @@ -3213,51 +3248,68 @@ void AppIdSession::processCHP(char** version, Packet* p) } } - 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; @@ -3287,25 +3339,17 @@ void AppIdSession::processCHP(char** version, Packet* p) } 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) { @@ -3326,6 +3370,7 @@ void AppIdSession::processCHP(char** version, Packet* p) username_service = serviceAppId; set_session_flags(APPID_SESSION_LOGIN_SUCCEEDED); } + for (i = 0; i < NUMBER_OF_PTYPES; i++) { if (nullptr != chp_rewritten[i]) @@ -3336,6 +3381,7 @@ void AppIdSession::processCHP(char** version, Packet* p) 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; } } @@ -3368,6 +3414,7 @@ void AppIdSession::processCHP(char** version, Packet* p) } int AppIdSession::processHTTPPacket(int direction) + { Profile http_profile_context(httpPerfStats); constexpr auto RESPONSE_CODE_LENGTH = 3; @@ -3386,7 +3433,6 @@ int AppIdSession::processHTTPPacket(int direction) char* useragent; char* referer; char* via; - AppInfoTableEntry* entry; http_session = hsession; if (!http_session) @@ -3416,9 +3462,8 @@ int AppIdSession::processHTTPPacket(int direction) 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); @@ -3500,8 +3545,7 @@ int AppIdSession::processHTTPPacket(int direction) } if (local_subtype) { - for (tmpSubtype = &subtype; *tmpSubtype; tmpSubtype = - &(*tmpSubtype)->next) + for (tmpSubtype = &subtype; *tmpSubtype; tmpSubtype = &(*tmpSubtype)->next) ; *tmpSubtype = local_subtype; @@ -3518,15 +3562,16 @@ int AppIdSession::processHTTPPacket(int direction) } // 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, @@ -3647,11 +3692,13 @@ int AppIdSession::processHTTPPacket(int direction) 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; @@ -3661,7 +3708,7 @@ int AppIdSession::processHTTPPacket(int direction) { 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; diff --git a/src/network_inspectors/appid/appid_session.h b/src/network_inspectors/appid/appid_session.h index 8e05b525a..f14709163 100644 --- a/src/network_inspectors/appid/appid_session.h +++ b/src/network_inspectors/appid/appid_session.h @@ -115,28 +115,35 @@ struct fflow_info 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; @@ -147,9 +154,7 @@ struct httpSession 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; @@ -187,16 +192,12 @@ struct tlsSession 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); @@ -207,7 +208,7 @@ public: AppIdConfig* config = nullptr; CommonAppIdData common; - AppIdSession* next = nullptr; + //AppIdSession* next = nullptr; Flow* flow = nullptr; AppIdFlowData* flowData = nullptr; AppInfoManager* app_info_mgr = nullptr; @@ -263,10 +264,10 @@ public: 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; @@ -351,6 +352,8 @@ public: 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*); @@ -373,7 +376,7 @@ private: 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*); @@ -383,7 +386,6 @@ private: 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); diff --git a/src/network_inspectors/appid/application_ids.h b/src/network_inspectors/appid/application_ids.h index 74369e707..3a84907a7 100644 --- a/src/network_inspectors/appid/application_ids.h +++ b/src/network_inspectors/appid/application_ids.h @@ -245,8 +245,6 @@ enum ApplicationId : int32_t 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, @@ -989,6 +987,7 @@ enum ApplicationId : int32_t 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, @@ -997,6 +996,9 @@ enum ApplicationId : int32_t 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 diff --git a/src/network_inspectors/appid/client_plugins/client_app_aim.cc b/src/network_inspectors/appid/client_plugins/client_app_aim.cc index dc82b8b5c..0f898c802 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_aim.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_aim.cc @@ -74,7 +74,7 @@ THREAD_LOCAL AIM_CLIENT_APP_CONFIG aim_config; #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*); @@ -123,7 +123,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_api.h b/src/network_inspectors/appid/client_plugins/client_app_api.h index ce9719051..e09c49997 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_api.h +++ b/src/network_inspectors/appid/client_plugins/client_app_api.h @@ -59,7 +59,7 @@ struct RNAClientAppModuleConfigItem 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); @@ -78,7 +78,7 @@ struct FinalizeClientAppAPI 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(*)(); diff --git a/src/network_inspectors/appid/client_plugins/client_app_base.cc b/src/network_inspectors/appid/client_plugins/client_app_base.cc index 4085f4e72..22c9f8191 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_base.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_base.cc @@ -41,7 +41,6 @@ #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" @@ -85,7 +84,7 @@ static void CClientAppRegisterPatternNoCase(RNAClientAppFCN fcn, IpProtocol prot 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, @@ -113,7 +112,6 @@ extern RNAClientAppModule http_client_mod; static RNAClientAppModule* static_client_list[] = { - &smtp_client_mod, &ssh_client_mod, &msn_client_mod, &aim_client_mod, @@ -337,6 +335,9 @@ int ClientAppLoadCallback(void* symbol) 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 @@ -870,26 +871,8 @@ static void ClientAppID(Packet* p, const int /*direction*/, AppIdSession* asd) 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) diff --git a/src/network_inspectors/appid/client_plugins/client_app_bit.cc b/src/network_inspectors/appid/client_plugins/client_app_bit.cc index ff12bcd10..aa6ebf910 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_bit.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_bit.cc @@ -71,7 +71,7 @@ struct BIT_CLIENT_APP_CONFIG 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); @@ -109,7 +109,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_bit_tracker.cc b/src/network_inspectors/appid/client_plugins/client_app_bit_tracker.cc index eaff50aec..63e7db63b 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_bit_tracker.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_bit_tracker.cc @@ -70,7 +70,7 @@ struct BIT_CLIENT_APP_CONFIG 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); @@ -110,7 +110,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_msn.cc b/src/network_inspectors/appid/client_plugins/client_app_msn.cc index 0b04ee903..9f4bebd74 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_msn.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_msn.cc @@ -69,7 +69,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_rtp.cc b/src/network_inspectors/appid/client_plugins/client_app_rtp.cc index 3e9c5e966..1e403a7e5 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_rtp.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_rtp.cc @@ -82,7 +82,7 @@ struct RTP_CLIENT_APP_CONFIG 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); @@ -231,7 +231,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_smtp.cc b/src/network_inspectors/appid/client_plugins/client_app_smtp.cc deleted file mode 100644 index 53971f5ec..000000000 --- a/src/network_inspectors/appid/client_plugins/client_app_smtp.cc +++ /dev/null @@ -1,696 +0,0 @@ -//-------------------------------------------------------------------------- -// 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; vadd_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; vadd_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; -} - diff --git a/src/network_inspectors/appid/client_plugins/client_app_smtp.h b/src/network_inspectors/appid/client_plugins/client_app_smtp.h deleted file mode 100644 index fabcb6c06..000000000 --- a/src/network_inspectors/appid/client_plugins/client_app_smtp.h +++ /dev/null @@ -1,30 +0,0 @@ -//-------------------------------------------------------------------------- -// 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 - diff --git a/src/network_inspectors/appid/client_plugins/client_app_ssh.cc b/src/network_inspectors/appid/client_plugins/client_app_ssh.cc index 3bf64bac0..27ac8cc37 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_ssh.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_ssh.cc @@ -153,7 +153,7 @@ struct SSH_CLIENT_CONFIG 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); @@ -199,7 +199,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_timbuktu.cc b/src/network_inspectors/appid/client_plugins/client_app_timbuktu.cc index d6b3e2e24..8e91368d5 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_timbuktu.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_timbuktu.cc @@ -68,7 +68,7 @@ struct TIMBUKTU_CLIENT_APP_CONFIG 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); @@ -106,7 +106,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_tns.cc b/src/network_inspectors/appid/client_plugins/client_app_tns.cc index 34c7e1ff7..bef4e8667 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_tns.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_tns.cc @@ -129,7 +129,7 @@ static const char* msg_type[] = #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); @@ -167,7 +167,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_vnc.cc b/src/network_inspectors/appid/client_plugins/client_app_vnc.cc index 9fee88d90..fc6c9605c 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_vnc.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_vnc.cc @@ -55,7 +55,7 @@ struct VNC_CLIENT_APP_CONFIG 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); @@ -95,7 +95,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/client_app_ym.cc b/src/network_inspectors/appid/client_plugins/client_app_ym.cc index 3fd3a50b7..bde086cb6 100644 --- a/src/network_inspectors/appid/client_plugins/client_app_ym.cc +++ b/src/network_inspectors/appid/client_plugins/client_app_ym.cc @@ -39,7 +39,7 @@ THREAD_LOCAL YM_CLIENT_APP_CONFIG ym_config; #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); @@ -80,7 +80,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; diff --git a/src/network_inspectors/appid/client_plugins/test/Makefile.am b/src/network_inspectors/appid/client_plugins/test/Makefile.am deleted file mode 100644 index 3af23bf0e..000000000 --- a/src/network_inspectors/appid/client_plugins/test/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ - -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@ - diff --git a/src/network_inspectors/appid/detector_plugins/detector_base.cc b/src/network_inspectors/appid/detector_plugins/detector_base.cc index a5f0cf5d8..be47f60e8 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_base.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_base.cc @@ -25,6 +25,7 @@ #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, @@ -44,6 +45,7 @@ static RNADetectorValidationModule* static_detector_list[] { &imap_detector_mod, &pop3_detector_mod, + &smtp_detector_mod, &kerberos_detector_mod }; const uint32_t NUM_STATIC_DETECTORS = diff --git a/src/network_inspectors/appid/detector_plugins/detector_dns.cc b/src/network_inspectors/appid/detector_plugins/detector_dns.cc index 5cb44ffa7..bebd51350 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_dns.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_dns.cc @@ -143,7 +143,7 @@ struct MatchedDNSPatterns 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*); @@ -198,8 +198,8 @@ static AppRegistryEntry appIdRegistry[] = { 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, @@ -244,12 +244,12 @@ struct ServiceDnsConfig }; 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; } @@ -312,7 +312,7 @@ int dns_host_detector_process_patterns() 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++) diff --git a/src/network_inspectors/appid/detector_plugins/detector_http.cc b/src/network_inspectors/appid/detector_plugins/detector_http.cc index eaaf62610..be97f20be 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_http.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_http.cc @@ -344,6 +344,7 @@ public: 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; }; @@ -421,6 +422,48 @@ void insert_http_pattern_element(enum httpPatternType pType, HTTPListElement* el } } +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; @@ -603,7 +646,7 @@ static int http_pattern_match(void* id, void*, int index, void* data, void*) 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; @@ -709,19 +752,16 @@ static SearchTool* processContentTypePatterns(DetectorHTTPPattern* patternList, 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(); @@ -767,6 +807,102 @@ static SearchTool* registerHeaderPatterns(HeaderPattern* patternList, size_t pat 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; @@ -812,6 +948,11 @@ int finalize_http_detector() 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; @@ -825,6 +966,7 @@ void clean_http_detector() 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]; @@ -902,7 +1044,7 @@ static char* normalize_userid(char* user) 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); @@ -2388,10 +2530,10 @@ bool is_webdav_found(HeaderMatchedPatterns* hmp) // 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[] = @@ -2474,7 +2616,7 @@ RNAServiceValidationModule http_service_mod = 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) { @@ -2512,7 +2654,7 @@ static CLIENT_APP_RETCODE http_client_validate(const uint8_t*, uint16_t, const i 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++) diff --git a/src/network_inspectors/appid/detector_plugins/detector_http.h b/src/network_inspectors/appid/detector_plugins/detector_http.h index b5edaac0b..ad026b35e 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_http.h +++ b/src/network_inspectors/appid/detector_plugins/detector_http.h @@ -159,12 +159,15 @@ int finalize_http_detector(); 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; diff --git a/src/network_inspectors/appid/detector_plugins/detector_imap.cc b/src/network_inspectors/appid/detector_plugins/detector_imap.cc index 4d861d5e2..749a1f573 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_imap.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_imap.cc @@ -74,7 +74,7 @@ struct ClientAppData 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); @@ -230,7 +230,7 @@ struct ServiceIMAPData #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 = @@ -287,7 +287,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; @@ -336,7 +336,7 @@ static CLIENT_APP_RETCODE init(const IniClientAppAPI* const init_api, SF_LIST* c 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"); diff --git a/src/network_inspectors/appid/detector_plugins/detector_kerberos.cc b/src/network_inspectors/appid/detector_plugins/detector_kerberos.cc index f239560c6..8248783f8 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_kerberos.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_kerberos.cc @@ -110,7 +110,7 @@ struct DetectorData 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); @@ -149,7 +149,7 @@ static Detector_Pattern client_patterns[] = { 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 = @@ -209,7 +209,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; @@ -258,7 +258,7 @@ static CLIENT_APP_RETCODE krb_client_init(const IniClientAppAPI* const init_api, 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; diff --git a/src/network_inspectors/appid/detector_plugins/detector_pattern.cc b/src/network_inspectors/appid/detector_plugins/detector_pattern.cc index 9990ce8cc..a3f15ba12 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_pattern.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_pattern.cc @@ -34,15 +34,15 @@ static THREAD_LOCAL ClientPortPattern clientPortPattern; 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 = { @@ -183,7 +183,7 @@ static void read_patterns(PortPatternNode* portPatternList, PatternService** ser } // 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; @@ -507,7 +507,7 @@ void finalize_service_port_patterns() 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; @@ -747,14 +747,14 @@ fail: 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; } diff --git a/src/network_inspectors/appid/detector_plugins/detector_pop3.cc b/src/network_inspectors/appid/detector_plugins/detector_pop3.cc index 71e71c04a..d6ed64409 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_pop3.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_pop3.cc @@ -58,7 +58,7 @@ struct ClientPOP3Data 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); @@ -192,7 +192,7 @@ struct ServicePOP3Data 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 = @@ -246,7 +246,7 @@ static AppRegistryEntry appIdRegistry[] = { 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; @@ -302,7 +302,7 @@ static CLIENT_APP_RETCODE pop3_ca_init(const IniClientAppAPI* const init_api, SF 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"); diff --git a/src/network_inspectors/appid/detector_plugins/detector_sip.cc b/src/network_inspectors/appid/detector_plugins/detector_sip.cc index 835f7dc2c..bfc494267 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_sip.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_sip.cc @@ -97,11 +97,11 @@ struct DetectorSipConfig 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); @@ -179,7 +179,7 @@ struct ServiceSIPData 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 = @@ -213,7 +213,7 @@ SO_PUBLIC RNAServiceValidationModule sip_service_mod = 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; @@ -256,7 +256,7 @@ static void sip_clean() 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; @@ -687,7 +687,7 @@ void SipSessionSnortCallback(void*, ServiceEventType, void* data) 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); diff --git a/src/network_inspectors/appid/detector_plugins/detector_smtp.cc b/src/network_inspectors/appid/detector_plugins/detector_smtp.cc new file mode 100644 index 000000000..9de1c35d2 --- /dev/null +++ b/src/network_inspectors/appid/detector_plugins/detector_smtp.cc @@ -0,0 +1,1035 @@ +/* +** 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; vadd_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; vadd_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 (; *offsetcode[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; +} diff --git a/src/network_inspectors/appid/service_plugins/service_smtp.h b/src/network_inspectors/appid/detector_plugins/detector_smtp.h similarity index 95% rename from src/network_inspectors/appid/service_plugins/service_smtp.h rename to src/network_inspectors/appid/detector_plugins/detector_smtp.h index 2318aaef9..a972d6675 100644 --- a/src/network_inspectors/appid/service_plugins/service_smtp.h +++ b/src/network_inspectors/appid/detector_plugins/detector_smtp.h @@ -24,7 +24,8 @@ #include "detector_plugins/detector_api.h" -extern RNAServiceValidationModule smtp_service_mod; +extern RNADetectorValidationModule smtp_detector_mod; + #endif diff --git a/src/network_inspectors/appid/client_plugins/test/CMakeLists.txt b/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt similarity index 68% rename from src/network_inspectors/appid/client_plugins/test/CMakeLists.txt rename to src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt index 0f73377be..be643af7d 100644 --- a/src/network_inspectors/appid/client_plugins/test/CMakeLists.txt +++ b/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt @@ -5,7 +5,7 @@ set ( 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} ) diff --git a/src/network_inspectors/appid/detector_plugins/test/Makefile.am b/src/network_inspectors/appid/detector_plugins/test/Makefile.am new file mode 100644 index 000000000..b768f87d2 --- /dev/null +++ b/src/network_inspectors/appid/detector_plugins/test/Makefile.am @@ -0,0 +1,15 @@ + +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@ + diff --git a/src/network_inspectors/appid/client_plugins/test/client_app_smtp_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc similarity index 99% rename from src/network_inspectors/appid/client_plugins/test/client_app_smtp_test.cc rename to src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc index 7768d032c..4a56f700c 100644 --- a/src/network_inspectors/appid/client_plugins/test/client_app_smtp_test.cc +++ b/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc @@ -19,7 +19,7 @@ // client_app_smtp_test.cc author Steve Chew // 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 #include diff --git a/src/network_inspectors/appid/lua_detector_api.cc b/src/network_inspectors/appid/lua_detector_api.cc index c229a5a35..19735ff71 100644 --- a/src/network_inspectors/appid/lua_detector_api.cc +++ b/src/network_inspectors/appid/lua_detector_api.cc @@ -1703,12 +1703,13 @@ static int detector_add_chp_action(AppId appIdInstance, int isKeyPattern, Patter 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); @@ -1728,8 +1729,36 @@ static int detector_add_chp_action(AppId appIdInstance, int isKeyPattern, Patter 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)); @@ -1748,14 +1777,19 @@ static int detector_add_chp_action(AppId appIdInstance, int isKeyPattern, Patter 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,"") == 0) + { + remove_http_patterns_for_id(appIdInstance); + } + return 0; } diff --git a/src/network_inspectors/appid/service_plugins/service_api.h b/src/network_inspectors/appid/service_plugins/service_api.h index 7261aa630..1af223c49 100644 --- a/src/network_inspectors/appid/service_plugins/service_api.h +++ b/src/network_inspectors/appid/service_plugins/service_api.h @@ -65,13 +65,13 @@ struct CleanServiceAPI 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); diff --git a/src/network_inspectors/appid/service_plugins/service_base.cc b/src/network_inspectors/appid/service_plugins/service_base.cc index ca787ae6a..412bb05f1 100644 --- a/src/network_inspectors/appid/service_plugins/service_base.cc +++ b/src/network_inspectors/appid/service_plugins/service_base.cc @@ -48,7 +48,6 @@ #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" @@ -193,7 +192,7 @@ static void appSetServiceValidator( RNAServiceValidationFCN, AppId, unsigned ext static int CServiceAddPort(const RNAServiceValidationPort*, RNAServiceValidationModule*); static void CServiceRemovePorts(RNAServiceValidationFCN validate); -static IniServiceAPI svc_init_api = +static InitServiceAPI svc_init_api = { &CServiceRegisterPattern, &CServiceAddPort, @@ -232,7 +231,6 @@ static RNAServiceValidationModule* static_service_list[] = &rshell_service_mod, &rsync_service_mod, &rtmp_service_mod, - &smtp_service_mod, &snmp_service_mod, &ssh_service_mod, &ssl_service_mod, diff --git a/src/network_inspectors/appid/service_plugins/service_battle_field.cc b/src/network_inspectors/appid/service_plugins/service_battle_field.cc index 0c7a55fcc..83f42a2fa 100644 --- a/src/network_inspectors/appid/service_plugins/service_battle_field.cc +++ b/src/network_inspectors/appid/service_plugins/service_battle_field.cc @@ -44,7 +44,7 @@ struct ServiceData 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 = @@ -96,7 +96,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_bgp.cc b/src/network_inspectors/appid/service_plugins/service_bgp.cc index b9b5aa02b..27e5392b8 100644 --- a/src/network_inspectors/appid/service_plugins/service_bgp.cc +++ b/src/network_inspectors/appid/service_plugins/service_bgp.cc @@ -86,7 +86,7 @@ struct ServiceBGPV1Open #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 = @@ -130,7 +130,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_bit.cc b/src/network_inspectors/appid/service_plugins/service_bit.cc index ba54191b0..758af5adf 100644 --- a/src/network_inspectors/appid/service_plugins/service_bit.cc +++ b/src/network_inspectors/appid/service_plugins/service_bit.cc @@ -66,7 +66,7 @@ struct ServiceBITMsg }; #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 = @@ -112,7 +112,7 @@ static AppRegistryEntry appIdRegistry[] = { 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); diff --git a/src/network_inspectors/appid/service_plugins/service_bootp.cc b/src/network_inspectors/appid/service_plugins/service_bootp.cc index 7fccf531b..f801abb90 100644 --- a/src/network_inspectors/appid/service_plugins/service_bootp.cc +++ b/src/network_inspectors/appid/service_plugins/service_bootp.cc @@ -66,7 +66,7 @@ struct ServiceDHCPOption #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 = @@ -105,7 +105,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_dcerpc.cc b/src/network_inspectors/appid/service_plugins/service_dcerpc.cc index 1525ccb48..8b0090f29 100644 --- a/src/network_inspectors/appid/service_plugins/service_dcerpc.cc +++ b/src/network_inspectors/appid/service_plugins/service_dcerpc.cc @@ -36,7 +36,7 @@ struct ServiceDCERPCData 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); @@ -87,7 +87,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_direct_connect.cc b/src/network_inspectors/appid/service_plugins/service_direct_connect.cc index 891c39ab5..a904afec1 100644 --- a/src/network_inspectors/appid/service_plugins/service_direct_connect.cc +++ b/src/network_inspectors/appid/service_plugins/service_direct_connect.cc @@ -44,7 +44,7 @@ struct ServiceData 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); @@ -101,7 +101,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_flap.cc b/src/network_inspectors/appid/service_plugins/service_flap.cc index 97654dbc0..afa23ba4c 100644 --- a/src/network_inspectors/appid/service_plugins/service_flap.cc +++ b/src/network_inspectors/appid/service_plugins/service_flap.cc @@ -74,7 +74,7 @@ struct FLAPHeader #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 = @@ -116,7 +116,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_ftp.cc b/src/network_inspectors/appid/service_plugins/service_ftp.cc index 74573a3dc..6dfd871a2 100644 --- a/src/network_inspectors/appid/service_plugins/service_ftp.cc +++ b/src/network_inspectors/appid/service_plugins/service_ftp.cc @@ -82,7 +82,7 @@ struct ServiceFTPCode #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 = @@ -130,7 +130,7 @@ static AppRegistryEntry appIdRegistry[] = 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_irc.cc b/src/network_inspectors/appid/service_plugins/service_irc.cc index 8183a852d..67bf44178 100644 --- a/src/network_inspectors/appid/service_plugins/service_irc.cc +++ b/src/network_inspectors/appid/service_plugins/service_irc.cc @@ -65,7 +65,7 @@ struct ServiceIRCData 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 = @@ -103,7 +103,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_lpr.cc b/src/network_inspectors/appid/service_plugins/service_lpr.cc index df424521a..6acb90e46 100644 --- a/src/network_inspectors/appid/service_plugins/service_lpr.cc +++ b/src/network_inspectors/appid/service_plugins/service_lpr.cc @@ -62,7 +62,7 @@ struct ServiceLPRData 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 = @@ -100,7 +100,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_mdns.cc b/src/network_inspectors/appid/service_plugins/service_mdns.cc index 82c2f8321..af2ece3f6 100644 --- a/src/network_inspectors/appid/service_plugins/service_mdns.cc +++ b/src/network_inspectors/appid/service_plugins/service_mdns.cc @@ -92,7 +92,7 @@ struct MdnsConfig 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); @@ -140,7 +140,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_mysql.cc b/src/network_inspectors/appid/service_plugins/service_mysql.cc index 52a56a6c3..97cdc633c 100644 --- a/src/network_inspectors/appid/service_plugins/service_mysql.cc +++ b/src/network_inspectors/appid/service_plugins/service_mysql.cc @@ -48,7 +48,7 @@ struct ServiceMYSQLHdr #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 @@ -86,7 +86,7 @@ static AppRegistryEntry appIdRegistry[] { 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++ ) { diff --git a/src/network_inspectors/appid/service_plugins/service_netbios.cc b/src/network_inspectors/appid/service_plugins/service_netbios.cc index b02047758..34a9de9c3 100644 --- a/src/network_inspectors/appid/service_plugins/service_netbios.cc +++ b/src/network_inspectors/appid/service_plugins/service_netbios.cc @@ -282,7 +282,7 @@ struct NBDgmError #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); @@ -344,7 +344,7 @@ RNAServiceValidationModule netbios_service_mod 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_nntp.cc b/src/network_inspectors/appid/service_plugins/service_nntp.cc index b28482567..c796acfec 100644 --- a/src/network_inspectors/appid/service_plugins/service_nntp.cc +++ b/src/network_inspectors/appid/service_plugins/service_nntp.cc @@ -62,7 +62,7 @@ struct ServiceNNTPCode #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 = @@ -103,7 +103,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_ntp.cc b/src/network_inspectors/appid/service_plugins/service_ntp.cc index ebfe60985..2735cf9f3 100644 --- a/src/network_inspectors/appid/service_plugins/service_ntp.cc +++ b/src/network_inspectors/appid/service_plugins/service_ntp.cc @@ -59,7 +59,7 @@ struct ServiceNTPOptional #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 = @@ -98,7 +98,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_radius.cc b/src/network_inspectors/appid/service_plugins/service_radius.cc index f449f67b8..806f6ae63 100644 --- a/src/network_inspectors/appid/service_plugins/service_radius.cc +++ b/src/network_inspectors/appid/service_plugins/service_radius.cc @@ -61,7 +61,7 @@ struct RADIUSHeader #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); @@ -116,7 +116,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_rexec.cc b/src/network_inspectors/appid/service_plugins/service_rexec.cc index 952b9f842..1b80016f7 100644 --- a/src/network_inspectors/appid/service_plugins/service_rexec.cc +++ b/src/network_inspectors/appid/service_plugins/service_rexec.cc @@ -64,7 +64,7 @@ struct ServiceREXECData 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 = @@ -104,7 +104,7 @@ static AppRegistryEntry appIdRegistry[] = 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; diff --git a/src/network_inspectors/appid/service_plugins/service_rfb.cc b/src/network_inspectors/appid/service_plugins/service_rfb.cc index 1ba4061a7..ebaa6c75c 100644 --- a/src/network_inspectors/appid/service_plugins/service_rfb.cc +++ b/src/network_inspectors/appid/service_plugins/service_rfb.cc @@ -32,7 +32,7 @@ #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 = @@ -78,7 +78,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_rlogin.cc b/src/network_inspectors/appid/service_plugins/service_rlogin.cc index b3e302ebf..e7b8f1515 100644 --- a/src/network_inspectors/appid/service_plugins/service_rlogin.cc +++ b/src/network_inspectors/appid/service_plugins/service_rlogin.cc @@ -44,7 +44,7 @@ struct ServiceRLOGINData 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 = @@ -82,7 +82,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_rpc.cc b/src/network_inspectors/appid/service_plugins/service_rpc.cc index d9f0af384..2e140cab6 100644 --- a/src/network_inspectors/appid/service_plugins/service_rpc.cc +++ b/src/network_inspectors/appid/service_plugins/service_rpc.cc @@ -161,7 +161,7 @@ struct ServiceRPCData 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); @@ -241,7 +241,7 @@ static AppRegistryEntry appIdRegistry[] = 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; diff --git a/src/network_inspectors/appid/service_plugins/service_rshell.cc b/src/network_inspectors/appid/service_plugins/service_rshell.cc index b0a743338..d9a9dc9f7 100644 --- a/src/network_inspectors/appid/service_plugins/service_rshell.cc +++ b/src/network_inspectors/appid/service_plugins/service_rshell.cc @@ -55,7 +55,7 @@ struct ServiceRSHELLData 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 = @@ -95,7 +95,7 @@ static AppRegistryEntry appIdRegistry[] = 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; @@ -204,8 +204,10 @@ static int rshell_validate(ServiceValidationArgs* args) } 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; diff --git a/src/network_inspectors/appid/service_plugins/service_rsync.cc b/src/network_inspectors/appid/service_plugins/service_rsync.cc index 3cab8babb..e2bbcc359 100644 --- a/src/network_inspectors/appid/service_plugins/service_rsync.cc +++ b/src/network_inspectors/appid/service_plugins/service_rsync.cc @@ -45,7 +45,7 @@ struct ServiceRSYNCData 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 = @@ -83,7 +83,7 @@ static AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_rtmp.cc b/src/network_inspectors/appid/service_plugins/service_rtmp.cc index 0c030ef89..16b84483b 100644 --- a/src/network_inspectors/appid/service_plugins/service_rtmp.cc +++ b/src/network_inspectors/appid/service_plugins/service_rtmp.cc @@ -80,7 +80,7 @@ struct ServiceRTMPData 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 = @@ -119,7 +119,7 @@ static AppRegistryEntry appIdRegistry[] = { 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++) diff --git a/src/network_inspectors/appid/service_plugins/service_smtp.cc b/src/network_inspectors/appid/service_plugins/service_smtp.cc deleted file mode 100644 index 89bd835bf..000000000 --- a/src/network_inspectors/appid/service_plugins/service_smtp.cc +++ /dev/null @@ -1,349 +0,0 @@ -//-------------------------------------------------------------------------- -// 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 (; *offsetcode[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; -} - diff --git a/src/network_inspectors/appid/service_plugins/service_snmp.cc b/src/network_inspectors/appid/service_plugins/service_snmp.cc index 0920046c2..83dcc8b8f 100644 --- a/src/network_inspectors/appid/service_plugins/service_snmp.cc +++ b/src/network_inspectors/appid/service_plugins/service_snmp.cc @@ -85,7 +85,7 @@ struct ServiceSNMPHeader #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 = @@ -131,7 +131,7 @@ static AppRegistryEntry appIdRegistry[] = 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_ssh.cc b/src/network_inspectors/appid/service_plugins/service_ssh.cc index 8e67314dd..e7182d476 100644 --- a/src/network_inspectors/appid/service_plugins/service_ssh.cc +++ b/src/network_inspectors/appid/service_plugins/service_ssh.cc @@ -127,7 +127,7 @@ struct ServiceSSHKeyExchangeFinal #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 = @@ -165,7 +165,7 @@ static const AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_ssl.cc b/src/network_inspectors/appid/service_plugins/service_ssl.cc index 020e92e50..2a6e93e2a 100644 --- a/src/network_inspectors/appid/service_plugins/service_ssl.cc +++ b/src/network_inspectors/appid/service_plugins/service_ssl.cc @@ -260,7 +260,7 @@ int ssl_detector_process_patterns() 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 = @@ -329,7 +329,7 @@ static const AppRegistryEntry appIdRegistry[] = { 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_telnet.cc b/src/network_inspectors/appid/service_plugins/service_telnet.cc index acc0455d9..9cf8ef670 100644 --- a/src/network_inspectors/appid/service_plugins/service_telnet.cc +++ b/src/network_inspectors/appid/service_plugins/service_telnet.cc @@ -68,7 +68,7 @@ struct ServiceTelnetData 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 = @@ -107,7 +107,7 @@ static const AppRegistryEntry appIdRegistry[] = { 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++) { diff --git a/src/network_inspectors/appid/service_plugins/service_tftp.cc b/src/network_inspectors/appid/service_plugins/service_tftp.cc index 04ef1e867..1ac017f27 100644 --- a/src/network_inspectors/appid/service_plugins/service_tftp.cc +++ b/src/network_inspectors/appid/service_plugins/service_tftp.cc @@ -76,7 +76,7 @@ struct ServiceTFTPHeader #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 = @@ -116,7 +116,7 @@ static const AppRegistryEntry appIdRegistry[] = 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"); diff --git a/src/network_inspectors/appid/service_plugins/service_timbuktu.cc b/src/network_inspectors/appid/service_plugins/service_timbuktu.cc index 5e6e1a526..13d3b1fc9 100644 --- a/src/network_inspectors/appid/service_plugins/service_timbuktu.cc +++ b/src/network_inspectors/appid/service_plugins/service_timbuktu.cc @@ -58,7 +58,7 @@ struct ServiceTIMBUKTUMsg }; #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 = @@ -96,7 +96,7 @@ static const AppRegistryEntry appIdRegistry[] = { 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, diff --git a/src/network_inspectors/appid/service_plugins/service_tns.cc b/src/network_inspectors/appid/service_plugins/service_tns.cc index 3f0874ded..7da715d4e 100644 --- a/src/network_inspectors/appid/service_plugins/service_tns.cc +++ b/src/network_inspectors/appid/service_plugins/service_tns.cc @@ -87,7 +87,7 @@ struct ServiceTNSMsg }; #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 = @@ -125,7 +125,7 @@ static const AppRegistryEntry appIdRegistry[] = { 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); diff --git a/src/network_inspectors/appid/test/appid_http_event_test.cc b/src/network_inspectors/appid/test/appid_http_event_test.cc index 34f219a75..90dd451bc 100644 --- a/src/network_inspectors/appid/test/appid_http_event_test.cc +++ b/src/network_inspectors/appid/test/appid_http_event_test.cc @@ -57,12 +57,14 @@ FlowData::~FlowData() 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; @@ -85,6 +87,12 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui 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) @@ -120,14 +128,20 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui 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); } } @@ -142,7 +156,7 @@ unsigned AppIdSession::flow_id = 0; 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) { } @@ -151,15 +165,31 @@ AppIdSession::~AppIdSession() 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); } @@ -194,7 +224,7 @@ AppIdSession* AppIdApi::get_appid_data(Flow*) 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) @@ -203,7 +233,16 @@ const uint8_t* HttpEvent::get_content_type(unsigned &length) 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) @@ -212,7 +251,16 @@ const uint8_t* HttpEvent::get_host(unsigned &length) 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) @@ -226,7 +274,7 @@ int32_t HttpEvent::get_response_code() 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) @@ -235,16 +283,16 @@ const uint8_t* HttpEvent::get_server(unsigned &length) 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) @@ -253,7 +301,7 @@ const uint8_t* HttpEvent::get_user_agent(unsigned &length) 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) @@ -262,7 +310,7 @@ const uint8_t* HttpEvent::get_via(unsigned &length) 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) @@ -311,7 +359,7 @@ TEST(appid_http_event, handle_null_msg_header) { 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; @@ -322,8 +370,10 @@ TEST(appid_http_event, handle_null_msg_header) } #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 @@ -337,12 +387,14 @@ struct TestData 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; }; @@ -351,20 +403,22 @@ void run_event_handler(TestData test_data, TestData *expect_data = 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) @@ -376,8 +430,10 @@ void run_event_handler(TestData test_data, TestData *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); @@ -412,12 +468,21 @@ TEST(appid_http_event, handle_msg_header_only_host) 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); } @@ -469,6 +534,17 @@ TEST(appid_http_event, handle_msg_header_content_type) 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; @@ -513,16 +589,18 @@ TEST(appid_http_event, handle_msg_header_all_response_headers) 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); } @@ -533,7 +611,8 @@ TEST(appid_http_event, handle_msg_header_all_request_headers) 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; @@ -545,6 +624,7 @@ TEST(appid_http_event, handle_msg_header_all_request_headers) // 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); } diff --git a/src/network_inspectors/appid/thirdparty_appid_types.h b/src/network_inspectors/appid/thirdparty_appid_types.h index 774d594ec..437b4111b 100644 --- a/src/network_inspectors/appid/thirdparty_appid_types.h +++ b/src/network_inspectors/appid/thirdparty_appid_types.h @@ -59,34 +59,54 @@ struct ThirdPartyAppIDAttributeData { 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 diff --git a/src/pub_sub/http_events.cc b/src/pub_sub/http_events.cc index 1b2b58284..a4881b903 100644 --- a/src/pub_sub/http_events.cc +++ b/src/pub_sub/http_events.cc @@ -23,7 +23,7 @@ #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); @@ -39,19 +39,31 @@ const uint8_t* HttpEvent::get_header(unsigned id, uint64_t sub_id, unsigned& len } } -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); @@ -62,30 +74,30 @@ int32_t HttpEvent::get_response_code() 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); diff --git a/src/pub_sub/http_events.h b/src/pub_sub/http_events.h index 422308026..f7f907290 100644 --- a/src/pub_sub/http_events.h +++ b/src/pub_sub/http_events.h @@ -40,20 +40,22 @@ public: { } - 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&); };