1 //--------------------------------------------------------------------------
2 // Copyright (C) 2018-2023 Cisco and/or its affiliates. All rights reserved.
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // service_state.cc author Masud Hasan <mashasan@cisco.com>
24 #include "network_inspectors/appid/service_state.cc"
26 #include <CppUTest/CommandLineTestRunner.h>
27 #include <CppUTest/TestHarness.h>
35 memset((char*) this , 0, sizeof(*this));
36 ip_proto_next
= IpProtocol::PROTO_NOT_SET
;
37 packet_flags
= PKT_FROM_CLIENT
;
39 Packet::~Packet() = default;
40 Packet
* DetectionEngine::get_current_packet() { return nullptr; }
44 void LogMessage(const char* format
, va_list& args
)
46 vsprintf(test_log
, format
, args
);
48 void LogMessage(const char* format
,...)
51 va_start(args
, format
);
52 LogMessage(format
, args
);
56 void LogLabel(const char*, FILE*) {}
57 void LogText(const char* s
, FILE*) { LogMessage("%s\n", s
); }
59 unsigned DataBus::get_id(const PubKey
&)
63 char* snort_strdup(const char* str
)
66 size_t n
= strlen(str
) + 1;
67 char* p
= (char*)snort_alloc(n
);
71 time_t packet_time() { return std::time(nullptr); }
73 AppIdSessionApi::AppIdSessionApi(const AppIdSession
*, const SfIp
&) :
74 StashGenericObject(STASH_GENERIC_OBJECT_APPID
) {}
77 DiscoveryFilter::~DiscoveryFilter(){}
78 // Stubs for AppInfoManager
79 AppInfoTableEntry
* AppInfoManager::get_app_info_entry(AppId
)
84 // Stubs for appid classes
85 class AppIdInspector
{};
86 FlowData::FlowData(unsigned, Inspector
*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
88 FlowData::~FlowData() = default;
90 // Stubs for AppIdDebug
91 THREAD_LOCAL AppIdDebug
* appidDebug
= nullptr;
92 THREAD_LOCAL AppIdStats appid_stats
;
94 void AppIdDebug::activate(const Flow
*, const AppIdSession
*, bool) { active
= true; }
96 void ApplicationDescriptor::set_id(const Packet
&, AppIdSession
&, AppidSessionDirection
, AppId
, AppidChangeBits
&) { }
97 void ApplicationDescriptor::set_id(AppId
){}
98 void ServiceAppDescriptor::set_id(AppId
, OdpContext
&){}
99 void ServiceAppDescriptor::set_port_service_id(AppId
){}
100 void ClientAppDescriptor::update_user(AppId
, const char*, AppidChangeBits
&){}
101 AppIdConfig::~AppIdConfig() = default;
102 OdpContext::OdpContext(const AppIdConfig
&, snort::SnortConfig
*) { }
103 AppIdConfig stub_config
;
104 AppIdContext
stub_ctxt(stub_config
);
105 OdpContext
stub_odp_ctxt(stub_config
, nullptr);
106 AppIdSession::AppIdSession(IpProtocol
, const SfIp
* ip
, uint16_t, AppIdInspector
&,
107 OdpContext
&, uint32_t) : FlowData(0), config(stub_config
),
108 api(*(new AppIdSessionApi(this, *ip
))), odp_ctxt(stub_odp_ctxt
) { }
109 AppIdSession::~AppIdSession() = default;
110 AppIdDiscovery::~AppIdDiscovery() = default;
111 void ClientDiscovery::initialize(AppIdInspector
&) { }
112 void ClientDiscovery::reload() { }
113 void AppIdDiscovery::register_detector(const std::string
&, AppIdDetector
*, IpProtocol
) {}
114 void AppIdDiscovery::add_pattern_data(AppIdDetector
*, SearchTool
&, int, const uint8_t* const,
115 unsigned, unsigned) {}
116 void AppIdDiscovery::register_tcp_pattern(AppIdDetector
*, const uint8_t* const, unsigned,
118 void AppIdDiscovery::register_udp_pattern(AppIdDetector
*, const uint8_t* const, unsigned,
120 int AppIdDiscovery::add_service_port(AppIdDetector
*,
121 const ServiceDetectorPort
&) { return APPID_EINVALID
; }
122 void ServiceDiscovery::initialize(AppIdInspector
&) {}
123 void ServiceDiscovery::reload() {}
124 void ServiceDiscovery::finalize_service_patterns() {}
125 void ServiceDiscovery::match_by_pattern(AppIdSession
&, const Packet
*, IpProtocol
) {}
126 void ServiceDiscovery::get_port_based_services(IpProtocol
, uint16_t, AppIdSession
&) {}
127 void ServiceDiscovery::get_next_service(const Packet
*, const AppidSessionDirection
, AppIdSession
&) {}
128 int ServiceDiscovery::identify_service(AppIdSession
&, Packet
*, AppidSessionDirection
,
129 AppidChangeBits
&) { return 0; }
130 int ServiceDiscovery::add_ftp_service_state(AppIdSession
&) { return 0; }
131 bool ServiceDiscovery::do_service_discovery(AppIdSession
&, Packet
*, AppidSessionDirection
,
132 AppidChangeBits
&) { return false; }
133 int ServiceDiscovery::incompatible_data(AppIdSession
&, const Packet
*,AppidSessionDirection
,
134 ServiceDetector
*) { return 0; }
135 int ServiceDiscovery::fail_service(AppIdSession
&, const Packet
*, AppidSessionDirection
,
136 ServiceDetector
*, ServiceDiscoveryState
*) { return 0; }
137 int ServiceDiscovery::add_service_port(AppIdDetector
*,
138 const ServiceDetectorPort
&) { return APPID_EINVALID
; }
139 DnsPatternMatchers::~DnsPatternMatchers() = default;
140 EveCaPatternMatchers::~EveCaPatternMatchers() = default;
141 HttpPatternMatchers::~HttpPatternMatchers() = default;
142 SipPatternMatchers::~SipPatternMatchers() = default;
143 SslPatternMatchers::~SslPatternMatchers() = default;
144 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
145 CipPatternMatchers::~CipPatternMatchers() = default;
146 snort::SearchTool::SearchTool(bool, const char*) { }
147 snort::SearchTool::~SearchTool() = default;
148 void appid_log(const snort::Packet
*, unsigned char, char const* fmt
, ...)
152 LogMessage(fmt
, args
);
156 TEST_GROUP(service_state_tests
)
158 void setup() override
160 appidDebug
= new AppIdDebug();
161 appidDebug
->activate(nullptr, nullptr, false);
164 void teardown() override
170 TEST(service_state_tests
, select_detector_by_brute_force
)
173 ServiceDiscoveryState sds
;
174 // Testing end of brute-force walk for supported and unsupported protocols
176 sds
.select_detector_by_brute_force(IpProtocol::TCP
, sd
);
177 STRCMP_EQUAL(test_log
, "Brute-force state failed - no more TCP detectors\n");
180 sds
.select_detector_by_brute_force(IpProtocol::UDP
, sd
);
181 STRCMP_EQUAL(test_log
, "Brute-force state failed - no more UDP detectors\n");
184 sds
.select_detector_by_brute_force(IpProtocol::IP
, sd
);
185 STRCMP_EQUAL(test_log
, "");
188 TEST(service_state_tests
, set_service_id_failed
)
190 ServiceDiscoveryState sds
;
191 AppIdInspector inspector
;
193 client_ip
.set("1.2.3.4");
194 AppIdSession
asd(IpProtocol::PROTO_NOT_SET
, &client_ip
, 0, inspector
, stub_odp_ctxt
);
196 // Testing 3+ failures to exceed STATE_ID_NEEDED_DUPE_DETRACT_COUNT with valid_count = 0
197 sds
.set_state(ServiceState::VALID
);
198 sds
.set_service_id_failed(asd
, &client_ip
, 0);
199 sds
.set_service_id_failed(asd
, &client_ip
, 0);
200 sds
.set_service_id_failed(asd
, &client_ip
, 0);
201 sds
.set_service_id_failed(asd
, &client_ip
, 0);
202 CHECK_TRUE(sds
.get_state() == ServiceState::SEARCHING_PORT_PATTERN
);
204 delete &asd
.get_api();
208 TEST(service_state_tests
, set_service_id_failed_with_valid
)
210 ServiceDiscoveryState sds
;
211 AppIdInspector inspector
;
213 client_ip
.set("1.2.3.4");
214 AppIdSession
asd(IpProtocol::PROTO_NOT_SET
, &client_ip
, 0, inspector
, stub_odp_ctxt
);
216 // Testing 3+ failures to exceed STATE_ID_NEEDED_DUPE_DETRACT_COUNT with valid_count > 1
217 sds
.set_state(ServiceState::VALID
);
218 sds
.set_service_id_valid(nullptr);
219 sds
.set_service_id_valid(nullptr);
220 sds
.set_service_id_failed(asd
, &client_ip
, 0);
221 sds
.set_service_id_failed(asd
, &client_ip
, 0);
222 sds
.set_service_id_failed(asd
, &client_ip
, 0);
223 sds
.set_service_id_failed(asd
, &client_ip
, 0);
224 CHECK_TRUE(sds
.get_state() == ServiceState::VALID
);
226 delete &asd
.get_api();
229 TEST(service_state_tests
, appid_service_state_key_comparison_test
)
233 ip6
.set("1111:2222:3333:4444:5555:6666:7777:8888");
234 IpProtocol proto
= IpProtocol::TCP
;
237 AppIdServiceStateKey
A(&ip4
, proto
, port
, 0, DAQ_PKTHDR_UNKNOWN
, false);
238 AppIdServiceStateKey
B(&ip6
, proto
, port
, 0, DAQ_PKTHDR_UNKNOWN
, false);
240 // We must never be in a situation where !( A<B ) and !( B<A ),
241 // because then map will consider A=B.
242 CHECK_TRUE(A
<B
|| B
<A
);
245 TEST(service_state_tests
, service_cache
)
247 size_t num_entries
= 10, max_entries
= 3;
248 size_t memcap
= max_entries
*MapList::sz
;
249 MapList
ServiceCache(memcap
);
251 IpProtocol proto
= IpProtocol::TCP
;
252 uint16_t port
= 3000;
255 ip6
.set("1111:2222:3333:4444:5555:6666:7777:8888");
257 ServiceDiscoveryState
* ss
= nullptr;
258 std::vector
<ServiceDiscoveryState
*> ssvec
;
261 // Insert (ipv4 and ipv6) past the memcap, and check the memcap is not exceeded.
262 for( size_t i
= 1; i
<= num_entries
; i
++, port
++ )
264 const SfIp
* ip
= ( i
%2 == 1 ? &ip4
: &ip6
);
265 ss
= ServiceCache
.add( AppIdServiceStateKey(ip
, proto
, port
, 0, DAQ_PKTHDR_UNKNOWN
, false) );
266 CHECK_TRUE(ServiceCache
.size() == ( i
<= max_entries
? i
: max_entries
));
270 // The cache should now be ip6:3007, ip4:3008, ip6:3009.
271 // Check that the order in the cache is correct.
272 Queue_t::iterator it
= ServiceCache
.newest();
273 std::vector
<ServiceDiscoveryState
*>::iterator vit
= --ssvec
.end();
274 for( size_t i
=0; i
<max_entries
; i
++, --it
, --vit
)
276 Map_t::iterator mit
= *it
;
277 CHECK_TRUE( mit
->second
== *vit
);
280 // Now get e.g. the oldest from the cache and check that it got touched:
281 it
= ServiceCache
.oldest();
282 ss
= ServiceCache
.get( (*it
)->first
, true );
283 CHECK_TRUE( ss
!= nullptr );
284 CHECK_TRUE( ss
->qptr
== ServiceCache
.newest() );
287 int main(int argc
, char** argv
)
289 int rc
= CommandLineTestRunner::RunAllTests(argc
, argv
);