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
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <anorokh@cisco.com>
+
+#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
+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
../../service_inspectors/http_inspect/http_test_input.cc
LIBS ${ZLIB_LIBRARIES}
)
+add_cpputest( pub_sub_ftp_events_test
+ SOURCES
+ ../ftp_events.h
+ $<TARGET_OBJECTS:extr_cpputest_deps>
+)
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <anorokh@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string>
+
+#include "pub_sub/ftp_events.h"
+#include "service_inspectors/ftp_telnet/ftpp_si.h"
+#include "utils/util_net.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+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<char*>(raw_response);
+ session.server.response.rsp_end = const_cast<char*>(raw_response) + 3;
+ session.server.response.rsp_size = 3;
+ session.server.response.msg_begin = const_cast<char*>(raw_response) + 4;
+ session.server.response.msg_end = const_cast<char*>(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);
+}
#include "config.h"
#endif
+#include <atomic>
+
+#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"
THREAD_LOCAL ProfileStats ftpPerfStats;
THREAD_LOCAL FtpStats ftstats;
+static std::atomic<unsigned> pub_id = 0;
+
//-------------------------------------------------------------------------
// implementation stuff
//-------------------------------------------------------------------------
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 ||
//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
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;
}
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);
}