From 1257ef8a829651dfd99f1d32a614f0f4c008b7aa Mon Sep 17 00:00:00 2001 From: "Vitalii Serhiiovych Horbatov -X (vhorbato - SOFTSERVE INC at Cisco)" Date: Fri, 7 Feb 2025 08:31:23 +0000 Subject: [PATCH] Pull request #4589: extractor: print null for fields that require missing packet context Merge in SNORT/snort3 from ~VHORBATO/snort3:extractor_no_pkt to master Squashed commit of the following: commit b190f237b7b9c5bb65fcd48e02f70d6ba20db0e1 Author: vhorbato Date: Tue Jan 28 18:24:14 2025 +0200 extractor: print null for fields that require missing packet context --- .../extractor/extractor_conn.cc | 22 +++---- .../extractor/extractor_conn.h | 4 +- .../extractor/extractor_ftp.cc | 63 ++++++++++--------- .../extractor/extractor_ftp.h | 4 +- .../extractor/extractor_http.cc | 52 ++++++++------- .../extractor/extractor_http.h | 4 +- src/network_inspectors/extractor/extractors.h | 52 +++++++++------ src/pub_sub/ftp_events.h | 6 -- src/pub_sub/test/pub_sub_ftp_events_test.cc | 6 -- 9 files changed, 105 insertions(+), 108 deletions(-) diff --git a/src/network_inspectors/extractor/extractor_conn.cc b/src/network_inspectors/extractor/extractor_conn.cc index 8d7c4fd3a..c9d965ce9 100644 --- a/src/network_inspectors/extractor/extractor_conn.cc +++ b/src/network_inspectors/extractor/extractor_conn.cc @@ -37,17 +37,17 @@ using namespace snort; using namespace std; -static uint64_t get_orig_pkts(const DataEvent*, const Packet*, const Flow* f) +static uint64_t get_orig_pkts(const DataEvent*, const Flow* f) { return f->flowstats.client_pkts; } -static uint64_t get_resp_pkts(const DataEvent*, const Packet*, const Flow* f) +static uint64_t get_resp_pkts(const DataEvent*, const Flow* f) { return f->flowstats.server_pkts; } -static uint64_t get_duration(const DataEvent*, const Packet*, const Flow* f) +static uint64_t get_duration(const DataEvent*, const Flow* f) { return f->last_data_seen - f->flowstats.start_time.tv_sec; } @@ -59,7 +59,7 @@ static const map sub_num_getters = {"duration", get_duration} }; -static const char* get_service(const DataEvent*, const Packet*, const Flow* f) +static const char* get_service(const DataEvent*, const Flow* f) { SnortConfig* sc = SnortConfig::get_main_conf(); return sc->proto_ref->get_name(f->ssn_state.snort_protocol_id); @@ -73,7 +73,7 @@ static const map pkttype_to_protocol = {PktType::ICMP, "ICMP"} }; -static const char* get_proto(const DataEvent*, const Packet*, const Flow* f) +static const char* get_proto(const DataEvent*, const Flow* f) { const auto& iter = pkttype_to_protocol.find(f->pkt_type); return (iter != pkttype_to_protocol.end()) ? iter->second.c_str() : ""; @@ -119,15 +119,13 @@ void ConnExtractor::handle(DataEvent& event, Flow* flow) if (flow->pkt_type < PktType::IP or flow->pkt_type > PktType::ICMP or !filter(flow)) return; - Packet* packet = (DetectionEngine::get_context()) ? DetectionEngine::get_current_packet() : nullptr; - extractor_stats.total_event++; logger->open_record(); - log(nts_fields, &event, packet, flow); - log(sip_fields, &event, packet, flow); - log(num_fields, &event, packet, flow); - log(buf_fields, &event, packet, flow); + log(nts_fields, &event, flow); + log(sip_fields, &event, flow); + log(num_fields, &event, flow); + log(buf_fields, &event, flow); logger->close_record(*log_id); } @@ -152,7 +150,7 @@ TEST_CASE("Conn Proto", "[extractor]") SECTION("unknown") { flow->pkt_type = PktType::NONE; - const char* proto = get_proto(nullptr, nullptr, flow); + const char* proto = get_proto(nullptr, flow); CHECK_FALSE(strcmp("", proto)); } diff --git a/src/network_inspectors/extractor/extractor_conn.h b/src/network_inspectors/extractor/extractor_conn.h index 83462a757..421d95dda 100644 --- a/src/network_inspectors/extractor/extractor_conn.h +++ b/src/network_inspectors/extractor/extractor_conn.h @@ -25,8 +25,8 @@ class ConnExtractor : public ExtractorEvent { public: - using ConnNumGetFn = uint64_t (*) (const DataEvent*, const Packet*, const Flow*); - using ConnNumField = DataField; + using ConnNumGetFn = uint64_t (*) (const DataEvent*, const Flow*); + using ConnNumField = DataField; ConnExtractor(Extractor&, uint32_t tenant, const std::vector& fields); diff --git a/src/network_inspectors/extractor/extractor_ftp.cc b/src/network_inspectors/extractor/extractor_ftp.cc index ac9d61370..c7f7f7672 100644 --- a/src/network_inspectors/extractor/extractor_ftp.cc +++ b/src/network_inspectors/extractor/extractor_ftp.cc @@ -45,19 +45,19 @@ using namespace std; namespace req { -static pair get_cmd(const DataEvent* event, const Packet*, const Flow*) +static pair get_cmd(const DataEvent* event, const Flow*) { const auto& req = ((const FtpRequestEvent*)event)->get_request(); return {req.cmd_begin, req.cmd_size}; } -static pair get_arg(const DataEvent* event, const Packet*, const Flow*) +static pair get_arg(const DataEvent* event, const Flow*) { const auto& req = ((const FtpRequestEvent*)event)->get_request(); return {req.param_begin, req.param_size}; } -static pair get_user(const DataEvent* event, const Packet*, const Flow*) +static pair get_user(const DataEvent* event, const Flow*) { const auto& req = ((const FtpRequestEvent*)event)->get_request(); const auto cmd = string(req.cmd_begin, req.cmd_size); @@ -109,13 +109,11 @@ void FtpRequestExtractor::handle(DataEvent& event, Flow* flow) extractor_stats.total_event++; - Packet* packet = DetectionEngine::get_current_packet(); - logger->open_record(); - log(nts_fields, &event, packet, flow); - log(sip_fields, &event, packet, flow); - log(num_fields, &event, packet, flow); - log(str_fields, &event, packet, flow, logger->is_strict()); + log(nts_fields, &event, flow); + log(sip_fields, &event, flow); + log(num_fields, &event, flow); + log(str_fields, &event, flow, logger->is_strict()); logger->close_record(*log_id); } @@ -141,19 +139,19 @@ static uint64_t parse_last_num(const char *str, uint16_t size) namespace resp { -static pair get_code(const DataEvent* event, const Packet*, const Flow*) +static pair get_code(const DataEvent* event, const Flow*) { const auto& response = ((const FtpResponseEvent*)event)->get_response(); return {response.rsp_begin, response.rsp_size}; } -static pair get_msg(const DataEvent* event, const Packet*, const Flow*) +static pair get_msg(const DataEvent* event, const Flow*) { const auto& response = ((const FtpResponseEvent*)event)->get_response(); return {response.msg_begin, response.msg_size}; } -static const SfIp& get_orig_ip(const DataEvent* event, const Packet*, const Flow*) +static const SfIp& get_orig_ip(const DataEvent* event, const Flow*) { if (((const FtpResponseEvent*)event)->is_passive()) return ((const FtpResponseEvent*)event)->get_client_ip(); @@ -161,7 +159,7 @@ static const SfIp& get_orig_ip(const DataEvent* event, const Packet*, const Flow return ((const FtpResponseEvent*)event)->get_server_ip(); } -static const SfIp& get_resp_ip(const DataEvent* event, const Packet*, const Flow*) +static const SfIp& get_resp_ip(const DataEvent* event, const Flow*) { if (((const FtpResponseEvent*)event)->is_passive()) return ((const FtpResponseEvent*)event)->get_server_ip(); @@ -169,7 +167,7 @@ static const SfIp& get_resp_ip(const DataEvent* event, const Packet*, const Flow return ((const FtpResponseEvent*)event)->get_client_ip(); } -static uint64_t get_resp_port(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_resp_port(const DataEvent* event, const Flow*) { if (((const FtpResponseEvent*)event)->is_passive()) return (uint64_t)((const FtpResponseEvent*)event)->get_server_port(); @@ -177,7 +175,7 @@ static uint64_t get_resp_port(const DataEvent* event, const Packet*, const Flow* return (uint64_t)((const FtpResponseEvent*)event)->get_client_port(); } -static uint64_t get_file_size(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_file_size(const DataEvent* event, const Flow*) { const auto& resp = ((const FtpResponseEvent*)event)->get_response(); const auto& code = string(resp.rsp_begin, resp.rsp_size); @@ -188,7 +186,7 @@ static uint64_t get_file_size(const DataEvent* event, const Packet*, const Flow* return 0; } -static int8_t get_mode(const DataEvent* event, const Packet*, const Flow*) +static int8_t get_mode(const DataEvent* event, const Flow*) { return ((const FtpResponseEvent*)event)->get_mode(); } @@ -248,12 +246,12 @@ void FtpResponseExtractor::internal_tinit(const snort::Connector::ID* service_id { log_id = service_id; } template<> -void ExtractorEvent::log, DataEvent*, Packet*, Flow*, bool>( - const vector& fields, DataEvent* event, Packet* pkt, Flow* flow, bool strict) +void ExtractorEvent::log, DataEvent*, Flow*, bool>( + const vector& fields, DataEvent* event, Flow* flow, bool strict) { for (const auto& f : fields) { - const auto mode = f.get(event, pkt, flow); + const auto mode = f.get(event, flow); if (mode != FTPP_XFER_NOT_SET) mode == FTPP_XFER_PASSIVE ? logger->add_field(f.name, true) : logger->add_field(f.name, false); else if (strict) @@ -271,14 +269,12 @@ void FtpResponseExtractor::handle(DataEvent& event, Flow* flow) extractor_stats.total_event++; - Packet* packet = DetectionEngine::get_current_packet(); - logger->open_record(); - log(nts_fields, &event, packet, flow); - log(sip_fields, &event, packet, flow); - log(num_fields, &event, packet, flow); - log(str_fields, &event, packet, flow, logger->is_strict()); - log(sub_fields, &event, packet, flow, logger->is_strict()); + log(nts_fields, &event, flow); + log(sip_fields, &event, flow); + log(num_fields, &event, flow); + log(str_fields, &event, flow, logger->is_strict()); + log(sub_fields, &event, flow, logger->is_strict()); logger->close_record(*log_id); } @@ -532,7 +528,6 @@ void FtpExtractor::Req::handle(DataEvent& event, Flow* flow) extractor_stats.total_event++; - Packet* p = DetectionEngine::get_current_packet(); auto fd = ExtractorFlowData::get(flow); if (!fd) @@ -541,9 +536,9 @@ void FtpExtractor::Req::handle(DataEvent& event, Flow* flow) { // log existing flow data owner.logger->open_record(); - owner.log(owner.nts_fields, &event, p, flow); - owner.log(owner.sip_fields, &event, p, flow); - owner.log(owner.num_fields, &event, p, flow); + owner.log(owner.nts_fields, &event, flow); + owner.log(owner.sip_fields, &event, flow); + owner.log(owner.num_fields, &event, flow); owner.log(owner.fd_buf_fields, (const FtpExtractorFlowData*)fd); owner.log(owner.fd_sip_fields, (const FtpExtractorFlowData*)fd); owner.log(owner.fd_num_fields, (const FtpExtractorFlowData*)fd); @@ -569,7 +564,13 @@ void FtpExtractor::Req::handle(DataEvent& event, Flow* flow) fd->cmd = cmd; fd->arg = string(req.param_begin, req.param_size); - fd->ts = p->pkth->ts; + const Packet* packet = ExtractorEvent::get_packet(); + + if (packet) + fd->ts = packet->pkth->ts; + else + snort::packet_gettimeofday(&fd->ts); + fd->has_data = true; } diff --git a/src/network_inspectors/extractor/extractor_ftp.h b/src/network_inspectors/extractor/extractor_ftp.h index 71daa31ae..a123b8527 100644 --- a/src/network_inspectors/extractor/extractor_ftp.h +++ b/src/network_inspectors/extractor/extractor_ftp.h @@ -44,8 +44,8 @@ private: class FtpResponseExtractor : public ExtractorEvent { public: - using SubGetFn = int8_t (*) (const DataEvent*, const Packet*, const Flow*); - using SubField = DataField; + using SubGetFn = int8_t (*) (const DataEvent*, const Flow*); + using SubField = DataField; FtpResponseExtractor(Extractor&, uint32_t tenant, const std::vector& fields); diff --git a/src/network_inspectors/extractor/extractor_http.cc b/src/network_inspectors/extractor/extractor_http.cc index 6ae7d3c4d..fad67d08c 100644 --- a/src/network_inspectors/extractor/extractor_http.cc +++ b/src/network_inspectors/extractor/extractor_http.cc @@ -37,37 +37,37 @@ using namespace snort; using namespace std; -static const Field& get_method(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_method(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_method(); } -static const Field& get_host(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_host(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_host_hdr(); } -static const Field& get_user_agent(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_user_agent(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_user_agent(); } -static const Field& get_uri(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_uri(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_uri(); } -static const Field& get_referrer(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_referrer(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_referer_hdr(); } -static const Field& get_origin(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_origin(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_origin_hdr(); } -static const char* get_version(const DataEvent* event, const Packet*, const Flow*) +static const char* get_version(const DataEvent* event, const Flow*) { HttpEnums::VersionId version = ((const HttpTransactionEndEvent*)event)->get_version(); const auto& iter = HttpEnums::VersionEnumToStr.find(version); @@ -75,52 +75,52 @@ static const char* get_version(const DataEvent* event, const Packet*, const Flow return iter != HttpEnums::VersionEnumToStr.end() ? iter->second : ""; } -static const Field& get_stat_code(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_stat_code(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_stat_code(); } -static const Field& get_stat_msg(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_stat_msg(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_stat_msg(); } -static uint64_t get_trans_depth(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_trans_depth(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_trans_depth(); } -static uint64_t get_request_body_len(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_request_body_len(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_request_body_len(); } -static uint64_t get_response_body_len(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_response_body_len(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_response_body_len(); } -static uint64_t get_info_code(const DataEvent* event, const Packet*, const Flow*) +static uint64_t get_info_code(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_info_code(); } -static const Field& get_info_msg(const DataEvent* event, const Packet*, const Flow*) +static const Field& get_info_msg(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_info_msg(); } -static const char* get_proxied(const DataEvent* event, const Packet*, const Flow*) +static const char* get_proxied(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_proxied().c_str(); } -static const char* get_orig_filenames(const DataEvent* event, const Packet*, const Flow*) +static const char* get_orig_filenames(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_filename(HttpCommon::SRC_CLIENT).c_str(); } -static const char* get_resp_filenames(const DataEvent* event, const Packet*, const Flow*) +static const char* get_resp_filenames(const DataEvent* event, const Flow*) { return ((const HttpTransactionEndEvent*)event)->get_filename(HttpCommon::SRC_SERVER).c_str(); } @@ -183,12 +183,12 @@ void HttpExtractor::internal_tinit(const snort::Connector::ID* service_id) { log_id = service_id; } template<> -void ExtractorEvent::log, DataEvent*, Packet*, Flow*, bool>( - const vector& fields, DataEvent* event, Packet* pkt, Flow* flow, bool strict) +void ExtractorEvent::log, DataEvent*, Flow*, bool>( + const vector& fields, DataEvent* event, Flow* flow, bool strict) { for (const auto& f : fields) { - const auto& field = f.get(event, pkt, flow); + const auto& field = f.get(event, flow); if (field.length() > 0) logger->add_field(f.name, (const char*)field.start(), field.length()); else if (strict) @@ -206,14 +206,12 @@ void HttpExtractor::handle(DataEvent& event, Flow* flow) extractor_stats.total_event++; - Packet* packet = DetectionEngine::get_current_packet(); - logger->open_record(); - log(nts_fields, &event, packet, flow); - log(sip_fields, &event, packet, flow); - log(num_fields, &event, packet, flow); - log(buf_fields, &event, packet, flow); - log(sub_fields, &event, packet, flow, logger->is_strict()); + log(nts_fields, &event, flow); + log(sip_fields, &event, flow); + log(num_fields, &event, flow); + log(buf_fields, &event, flow); + log(sub_fields, &event, flow, logger->is_strict()); logger->close_record(*log_id); } diff --git a/src/network_inspectors/extractor/extractor_http.h b/src/network_inspectors/extractor/extractor_http.h index 2c33f579c..c2f27d807 100644 --- a/src/network_inspectors/extractor/extractor_http.h +++ b/src/network_inspectors/extractor/extractor_http.h @@ -27,8 +27,8 @@ class Field; class HttpExtractor : public ExtractorEvent { public: - using SubGetFn = const Field& (*) (const DataEvent*, const Packet*, const Flow*); - using SubField = DataField; + using SubGetFn = const Field& (*) (const DataEvent*, const Flow*); + using SubField = DataField; HttpExtractor(Extractor&, uint32_t tenant, const std::vector& fields); diff --git a/src/network_inspectors/extractor/extractors.h b/src/network_inspectors/extractor/extractors.h index dd46ad8f2..fd23dccd4 100644 --- a/src/network_inspectors/extractor/extractors.h +++ b/src/network_inspectors/extractor/extractors.h @@ -52,16 +52,16 @@ public: using Packet = snort::Packet; using SfIp = snort::SfIp; - using BufGetFn = const char* (*) (const DataEvent*, const Packet*, const Flow*); - using BufField = DataField; - using SipGetFn = const SfIp& (*) (const DataEvent*, const Packet*, const Flow*); - using SipField = DataField; - using NumGetFn = uint64_t (*) (const DataEvent*, const Packet*, const Flow*); - using NumField = DataField; - using NtsGetFn = struct timeval (*) (const DataEvent*, const Packet*, const Flow*); - using NtsField = DataField; - using StrGetFn = std::pair (*) (const DataEvent*, const Packet*, const Flow*); - using StrField = DataField, const DataEvent*, const Packet*, const Flow*>; + using BufGetFn = const char* (*) (const DataEvent*, const Flow*); + using BufField = DataField; + using SipGetFn = const SfIp& (*) (const DataEvent*, const Flow*); + using SipField = DataField; + using NumGetFn = uint64_t (*) (const DataEvent*, const Flow*); + using NumField = DataField; + using NtsGetFn = struct timeval (*) (const DataEvent*, const Flow*); + using NtsField = DataField; + using StrGetFn = std::pair (*) (const DataEvent*, const Flow*); + using StrField = DataField, const DataEvent*, const Flow*>; static snort::FlowHashKeyOps& get_hash() { @@ -69,6 +69,9 @@ public: return flow_key_ops; } + static const snort::Packet* get_packet() + { return snort::DetectionEngine::get_context() ? snort::DetectionEngine::get_current_packet() : nullptr; } + virtual ~ExtractorEvent() {} void tinit(ExtractorLogger*, const snort::Connector::ID*); @@ -88,8 +91,10 @@ protected: T& owner; }; - static struct timeval get_timestamp(const DataEvent*, const Packet* p, const Flow*) + static struct timeval get_timestamp(const DataEvent*, const Flow*) { + const Packet* p = ExtractorEvent::get_packet(); + if (p != nullptr) return p->pkth->ts; @@ -98,22 +103,29 @@ protected: return timestamp; } - static const SfIp& get_ip_src(const DataEvent*, const Packet*, const Flow* flow) + static const SfIp& get_ip_src(const DataEvent*, const Flow* flow) { return flow->flags.client_initiated ? flow->client_ip : flow->server_ip; } - static const SfIp& get_ip_dst(const DataEvent*, const Packet*, const Flow* flow) + static const SfIp& get_ip_dst(const DataEvent*, const Flow* flow) { return flow->flags.client_initiated ? flow->server_ip : flow->client_ip; } - static uint64_t get_ip_src_port(const DataEvent*, const Packet*, const Flow* flow) + static uint64_t get_ip_src_port(const DataEvent*, const Flow* flow) { return flow->client_port; } - static uint64_t get_ip_dst_port(const DataEvent*, const Packet*, const Flow* flow) + static uint64_t get_ip_dst_port(const DataEvent*, const Flow* flow) { return flow->server_port; } - static uint64_t get_pkt_num(const DataEvent*, const Packet* p, const Flow*) - { return (p != nullptr) ? p->context->packet_number : 0; } + static uint64_t get_pkt_num(const DataEvent*, const Flow*) + { + const Packet* p = ExtractorEvent::get_packet(); + + if (p != nullptr) + return p->context->packet_number; + + return 0; + } - static uint64_t get_uid(const DataEvent*, const Packet*, const Flow* flow) + static uint64_t get_uid(const DataEvent*, const Flow* flow) { return ExtractorEvent::get_hash().do_hash((const unsigned char*)flow->key, 0); } template @@ -123,11 +135,11 @@ protected: logger->add_field(f.name, f.get(context...)); } - void log(const std::vector& fields, DataEvent* event, Packet* pkt, Flow* flow, bool strict) + void log(const std::vector& fields, DataEvent* event, Flow* flow, bool strict) { for (const auto& f : fields) { - const auto& str = f.get(event, pkt, flow); + const auto& str = f.get(event, flow); if (str.second > 0) logger->add_field(f.name, (const char*)str.first, str.second); else if (strict) diff --git a/src/pub_sub/ftp_events.h b/src/pub_sub/ftp_events.h index 9bf267262..62be75f09 100644 --- a/src/pub_sub/ftp_events.h +++ b/src/pub_sub/ftp_events.h @@ -47,12 +47,6 @@ public: 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; }; diff --git a/src/pub_sub/test/pub_sub_ftp_events_test.cc b/src/pub_sub/test/pub_sub_ftp_events_test.cc index 81187ec17..dfa85addd 100644 --- a/src/pub_sub/test/pub_sub_ftp_events_test.cc +++ b/src/pub_sub/test/pub_sub_ftp_events_test.cc @@ -89,12 +89,6 @@ TEST(pub_sub_ftp_events_test, ftp_request_event) 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) -- 2.47.3