From: Anna Norokh -X (anorokh - SOFTSERVE INC at Cisco) Date: Fri, 27 Sep 2024 14:03:54 +0000 (+0000) Subject: Pull request #4449: pub_sub: add request and response events X-Git-Tag: 3.4.0.0~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db6de150b4c7df6e3a2f6f15b709bf6b1213a31c;p=thirdparty%2Fsnort3.git Pull request #4449: pub_sub: add request and response events Merge in SNORT/snort3 from ~ANOROKH/snort3:extractor_ftp_event to master Squashed commit of the following: commit 45a8734430fa07e7e0898180e82508531efe0cdd Author: anorokh Date: Mon Sep 16 16:19:15 2024 +0300 pub_sub: add request and response FTP events --- diff --git a/src/pub_sub/CMakeLists.txt b/src/pub_sub/CMakeLists.txt index 2306be514..29710692b 100644 --- a/src/pub_sub/CMakeLists.txt +++ b/src/pub_sub/CMakeLists.txt @@ -12,6 +12,7 @@ set (PUB_SUB_INCLUDES expect_events.h external_event_ids.h finalize_packet_event.h + ftp_events.h http_event_ids.h http_events.h http_request_body_event.h diff --git a/src/pub_sub/ftp_events.h b/src/pub_sub/ftp_events.h new file mode 100644 index 000000000..1d0fab6c6 --- /dev/null +++ b/src/pub_sub/ftp_events.h @@ -0,0 +1,86 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2024 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// ftp_events.h author Anna Norokh + +#ifndef FTP_EVENTS_H +#define FTP_EVENTS_H + +#include "framework/data_bus.h" +#include "service_inspectors/ftp_telnet/ftpp_si.h" + +namespace snort +{ + +struct FtpEventIds +{ + enum : unsigned + { + FTP_REQUEST, + FTP_RESPONSE, + MAX + }; +}; + +const snort::PubKey ftp_pub_key { "ftp", FtpEventIds::MAX }; + +class SO_PUBLIC FtpRequestEvent : public snort::DataEvent +{ +public: + FtpRequestEvent(const FTP_SESSION& ssn) : session(ssn) { } + + const FTP_CLIENT_REQ& get_request() const + { return session.client.request; } + + uint64_t get_client_port() const + { return (uint64_t)session.clientPort; } + + const snort::SfIp& get_client_ip() const + { return session.clientIP; } + +private: + const FTP_SESSION& session; +}; + +class SO_PUBLIC FtpResponseEvent : public snort::DataEvent +{ +public: + FtpResponseEvent(const FTP_SESSION& ssn) : session(ssn) { } + + const FTP_SERVER_RSP& get_response() const + { return session.server.response; } + + uint64_t get_client_port() const + { return (uint64_t)session.clientPort; } + + uint64_t get_server_port() const + { return (uint64_t)session.serverPort; } + + const snort::SfIp& get_client_ip() const + { return session.clientIP; } + + const snort::SfIp& get_server_ip() const + { return session.serverIP; } + +private: + const FTP_SESSION& session; +}; + +} + +#endif diff --git a/src/pub_sub/test/CMakeLists.txt b/src/pub_sub/test/CMakeLists.txt index 568ba067a..f2a21d8aa 100644 --- a/src/pub_sub/test/CMakeLists.txt +++ b/src/pub_sub/test/CMakeLists.txt @@ -1,3 +1,9 @@ +if ( ENABLE_UNIT_TESTS ) + add_library(extr_cpputest_deps OBJECT EXCLUDE_FROM_ALL + ../../sfip/sf_ip.cc + ) +endif ( ENABLE_UNIT_TESTS ) + add_cpputest( pub_sub_http_event_test SOURCES ../http_events.cc @@ -20,3 +26,8 @@ add_cpputest( pub_sub_http_transaction_end_event_test ../../service_inspectors/http_inspect/http_test_input.cc LIBS ${ZLIB_LIBRARIES} ) +add_cpputest( pub_sub_ftp_events_test + SOURCES + ../ftp_events.h + $ +) diff --git a/src/pub_sub/test/pub_sub_ftp_events_test.cc b/src/pub_sub/test/pub_sub_ftp_events_test.cc new file mode 100644 index 000000000..81187ec17 --- /dev/null +++ b/src/pub_sub/test/pub_sub_ftp_events_test.cc @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2024 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// ftp_events.h author Anna Norokh + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "pub_sub/ftp_events.h" +#include "service_inspectors/ftp_telnet/ftpp_si.h" +#include "utils/util_net.h" + +#include +#include +#include + +using namespace snort; + +namespace snort +{ +void* snort_alloc(size_t sz) +{ return new uint8_t[sz]; } + +char* snort_strdup(const char* str) +{ + assert(str); + size_t n = strlen(str) + 1; + char* p = (char*)snort_alloc(n); + memcpy(p, str, n); + return p; +} +} + +static FTP_SESSION session; + +TEST_GROUP(pub_sub_ftp_events_test) +{ + const char* raw_request = "RETR file.txt\r\n"; + const char* raw_response = "226 Transfer complete.\r\n"; + + void setup() override + { + session.client.request.cmd_begin = raw_request; + session.client.request.cmd_end = raw_request + 4; + session.client.request.cmd_size = 4; + session.client.request.param_begin = raw_request + 5; + session.client.request.param_end = raw_request + 13; + session.client.request.param_size = 8; + + session.server.response.rsp_begin = const_cast(raw_response); + session.server.response.rsp_end = const_cast(raw_response) + 3; + session.server.response.rsp_size = 3; + session.server.response.msg_begin = const_cast(raw_response) + 4; + session.server.response.msg_end = const_cast(raw_response) + 22; + session.server.response.msg_size = 18; + + session.clientIP.set("10.10.10.1"); + session.serverIP.set("10.10.10.2"); + session.clientPort = 40000; + session.serverPort = 20; + } +}; + +TEST(pub_sub_ftp_events_test, ftp_request_event) +{ + FtpRequestEvent event(session); + + auto cmd = std::string(event.get_request().cmd_begin, event.get_request().cmd_size); + auto param = std::string(event.get_request().param_begin, event.get_request().param_size); + CHECK(cmd == "RETR"); + CHECK(event.get_request().cmd_size == 4); + CHECK(param == "file.txt"); + CHECK(event.get_request().param_size == 8); + + InetBuf src; + sfip_ntop(&event.get_client_ip(), src, sizeof(src)); + std::string client = src; + CHECK(client == "10.10.10.1"); + CHECK(event.get_client_port() == 40000); +} + +TEST(pub_sub_ftp_events_test, ftp_response_event) +{ + const FtpResponseEvent event(session); + + auto response = event.get_response(); + auto rsp = std::string(response.rsp_begin, response.rsp_size); + auto msg = std::string(response.msg_begin, response.msg_size); + CHECK(rsp == "226"); + CHECK(response.rsp_size == 3); + CHECK(msg == "Transfer complete."); + CHECK(response.msg_size == 18); + + InetBuf dst, src; + sfip_ntop(&event.get_client_ip(), src, sizeof(src)); + sfip_ntop(&event.get_server_ip(), dst, sizeof(dst)); + std::string client = src; + std::string server = dst; + CHECK(client == "10.10.10.1"); + CHECK(event.get_client_port() == 40000); + CHECK(server == "10.10.10.2"); + CHECK(event.get_server_port() == 20); + +} + +int main(int argc, char** argv) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} diff --git a/src/service_inspectors/ftp_telnet/ftp.cc b/src/service_inspectors/ftp_telnet/ftp.cc index 37ae42e35..51f67c422 100644 --- a/src/service_inspectors/ftp_telnet/ftp.cc +++ b/src/service_inspectors/ftp_telnet/ftp.cc @@ -21,10 +21,14 @@ #include "config.h" #endif +#include + +#include "framework/data_bus.h" #include "framework/pig_pen.h" #include "main/snort_config.h" #include "profiler/profiler.h" #include "protocols/packet.h" +#include "pub_sub/ftp_events.h" #include "stream/stream.h" #include "target_based/snort_protocols.h" #include "utils/util.h" @@ -51,6 +55,8 @@ SnortProtocolId ftp_data_snort_protocol_id = UNKNOWN_PROTOCOL_ID; THREAD_LOCAL ProfileStats ftpPerfStats; THREAD_LOCAL FtpStats ftstats; +static std::atomic pub_id = 0; + //------------------------------------------------------------------------- // implementation stuff //------------------------------------------------------------------------- @@ -60,16 +66,28 @@ static inline int InspectClientPacket(Packet* p) return p->has_paf_payload(); } +static void publish_ftp_request(const FTP_SESSION& session, Flow* flow) +{ + FtpRequestEvent event(session); + DataBus::publish(pub_id, FtpEventIds::FTP_REQUEST, event, flow); +} + +static void publish_ftp_response(const FTP_SESSION& session, Flow* flow) +{ + FtpResponseEvent event(session); + DataBus::publish(pub_id, FtpEventIds::FTP_RESPONSE, event, flow); +} + static int SnortFTP( FTP_SESSION* FTPsession, Packet* p, int iInspectMode) { // cppcheck-suppress unreadVariable Profile profile(ftpPerfStats); - if ( !FTPsession || !FTPsession->server_conf || !FTPsession->client_conf ) + if (!FTPsession || !FTPsession->server_conf || !FTPsession->client_conf) return FTPP_INVALID_SESSION; - if ( !FTPsession->server_conf->check_encrypted_data ) + if (!FTPsession->server_conf->check_encrypted_data) { if ( FTPsession->encr_state == AUTH_TLS_ENCRYPTED || FTPsession->encr_state == AUTH_SSL_ENCRYPTED || @@ -84,15 +102,15 @@ static int SnortFTP( //if ( !ScPafEnabled() ) Stream::flush_client(p); } - else if ( !InspectClientPacket(p) ) + else if (!InspectClientPacket(p)) return FTPP_SUCCESS; int ret = initialize_ftp(FTPsession, p, iInspectMode); - if ( ret ) + if (ret) return ret; ret = check_ftp(FTPsession, p, iInspectMode); - if ( ret == FTPP_SUCCESS ) + if (ret == FTPP_SUCCESS) { // FIXIT-L ideally do_detection will look at the cmd & param buffers // or the rsp & msg buffers. We should call it from inside check_ftp @@ -101,6 +119,13 @@ static int SnortFTP( do_detection(p); } + assert(FTPsession); + + if (iInspectMode == FTPP_SI_CLIENT_MODE) + publish_ftp_request(*FTPsession, p->flow); + else if (iInspectMode == FTPP_SI_SERVER_MODE) + publish_ftp_response(*FTPsession, p->flow); + return ret; } @@ -238,6 +263,7 @@ FtpServer::~FtpServer () bool FtpServer::configure(SnortConfig* sc) { + pub_id = DataBus::get_id(ftp_pub_key); ftp_data_snort_protocol_id = sc->proto_ref->add("ftp-data"); return !FTPCheckConfigs(sc, ftp_server); }