1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2006-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 // host_attributes.cc author davis mcpherson <davmcphe@cisco.com>
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "host_attributes.h"
27
28 #include "hash/lru_cache_shared.h"
29 #include "main/shell.h"
30 #include "main/snort.h"
31 #include "main/snort_config.h"
32 #include "main/thread.h"
33
34 using namespace snort;
35
36 static const PegInfo host_attribute_pegs[] =
37 {
38 { CountType::MAX, "total_hosts", "maximum number of entries in the host attribute table" },
39 { CountType::SUM, "hosts_pruned", "number of LRU hosts pruned due to configured resource limits" },
40 { CountType::SUM, "dynamic_host_adds", "number of host additions after initial host file load" },
41 { CountType::SUM, "dynamic_service_adds", "number of service additions after initial host file load" },
42 { CountType::SUM, "dynamic_service_updates", "number of service updates after initial host file load" },
43 { CountType::SUM, "service_list_overflows", "number of service additions that failed due to configured resource limits" },
44 { CountType::END, nullptr, nullptr }
45 };
46
47 template<typename Key, typename Value, typename Hash>
48 class HostLruSharedCache : public LruCacheShared<Key, Value, Hash>
49 {
50 public:
HostLruSharedCache(const size_t initial_size)51 HostLruSharedCache(const size_t initial_size) : LruCacheShared<Key, Value, Hash>(initial_size)
52 { }
53 };
54
55 typedef HostLruSharedCache<snort::SfIp, HostAttributesDescriptor, HostAttributesCacheKey> HostAttributesSharedCache;
56
57 class HostAttributesReloadTuner : public snort::ReloadResourceTuner
58 {
59 public:
60 HostAttributesReloadTuner() = default;
61
tinit()62 bool tinit() override
63 {
64 HostAttributesManager::initialize();
65 return true;
66 }
67
tune_packet_context()68 bool tune_packet_context() override
69 { return true; }
70
tune_idle_context()71 bool tune_idle_context() override
72 { return true; }
73 };
74
75 static THREAD_LOCAL HostAttributesSharedCache* active_cache = nullptr;
76 static HostAttributesSharedCache* swap_cache = nullptr;
77 static HostAttributesSharedCache* next_cache = nullptr;
78 static HostAttributesSharedCache* old_cache = nullptr;
79 static THREAD_LOCAL HostAttributeStats host_attribute_stats;
80
update_service(uint16_t port,uint16_t protocol,SnortProtocolId snort_protocol_id,bool & updated,bool is_appid_service)81 bool HostAttributesDescriptor::update_service
82 (uint16_t port, uint16_t protocol, SnortProtocolId snort_protocol_id, bool& updated,
83 bool is_appid_service)
84 {
85 std::lock_guard<std::mutex> lck(host_attributes_lock);
86
87 for ( auto& s : services)
88 {
89 if ( s.ipproto == protocol && (uint16_t)s.port == port )
90 {
91 if ( s.snort_protocol_id != snort_protocol_id )
92 {
93 s.snort_protocol_id = snort_protocol_id;
94 s.appid_service = is_appid_service;
95 }
96 updated = true;
97 return true;
98 }
99 }
100
101 // service not found, add it
102 if ( services.size() < SnortConfig::get_conf()->get_max_services_per_host() )
103 {
104 updated = false;
105 services.emplace_back(HostServiceDescriptor(port, protocol, snort_protocol_id, is_appid_service));
106 return true;
107 }
108
109 return false;
110 }
111
clear_appid_services()112 void HostAttributesDescriptor::clear_appid_services()
113 {
114 std::lock_guard<std::mutex> lck(host_attributes_lock);
115 for ( auto s = services.begin(); s != services.end(); )
116 {
117 if ( s->appid_service and s->snort_protocol_id != UNKNOWN_PROTOCOL_ID )
118 s = services.erase(s);
119 else
120 s++;
121 }
122 }
123
get_host_attributes(uint16_t port,HostAttriInfo * host_info) const124 void HostAttributesDescriptor::get_host_attributes(uint16_t port,HostAttriInfo* host_info) const
125 {
126 std::lock_guard<std::mutex> slk(host_attributes_lock);
127 host_info->frag_policy = policies.fragPolicy;
128 host_info->stream_policy = policies.streamPolicy;
129 host_info->snort_protocol_id = UNKNOWN_PROTOCOL_ID;
130 for ( auto& s : services )
131 {
132 if ( s.port == port )
133 {
134 host_info->snort_protocol_id = s.snort_protocol_id;
135 return;
136 }
137 }
138 }
load_hosts_file(snort::SnortConfig * sc,const char * fname)139 bool HostAttributesManager::load_hosts_file(snort::SnortConfig* sc, const char* fname)
140 {
141 delete next_cache;
142 next_cache = new HostAttributesSharedCache(sc->max_attribute_hosts);
143
144 Shell sh(fname);
145 if ( sh.configure(sc, true) )
146 {
147 activate(sc);
148 return true;
149 }
150
151 // loading of host file failed...
152 load_failure_cleanup();
153 return false;
154 }
155
add_host(HostAttributesEntry host,snort::SnortConfig * sc)156 bool HostAttributesManager::add_host(HostAttributesEntry host, snort::SnortConfig* sc)
157 {
158 if ( !next_cache )
159 next_cache = new HostAttributesSharedCache(sc->max_attribute_hosts);
160
161 return next_cache->find_else_insert(host->get_ip_addr(), host, true);
162 }
163
activate(SnortConfig * sc)164 void HostAttributesManager::activate(SnortConfig* sc)
165 {
166 if ( next_cache == nullptr )
167 return;
168 old_cache = active_cache;
169 active_cache = next_cache;
170 swap_cache = next_cache;
171 next_cache = nullptr;
172
173 if( active_cache != old_cache and Snort::is_reloading() )
174 sc->register_reload_resource_tuner(new HostAttributesReloadTuner);
175 }
176
initialize()177 void HostAttributesManager::initialize()
178 { active_cache = swap_cache; }
179
load_failure_cleanup()180 void HostAttributesManager::load_failure_cleanup()
181 {
182 delete next_cache;
183 next_cache = nullptr;
184 }
185
swap_cleanup()186 void HostAttributesManager::swap_cleanup()
187 {
188 delete old_cache;
189 old_cache = nullptr;
190 }
191
term()192 void HostAttributesManager::term()
193 { delete active_cache; }
194
get_host_attributes(const snort::SfIp & host_ip,uint16_t port,HostAttriInfo * host_info)195 bool HostAttributesManager::get_host_attributes(const snort::SfIp& host_ip, uint16_t port, HostAttriInfo* host_info)
196 {
197 if ( !active_cache )
198 return false;
199
200 HostAttributesEntry h = active_cache->find(host_ip);
201 if (h)
202 {
203 h->get_host_attributes(port, host_info);
204 return true;
205 }
206 return false;
207 }
208
update_service(const snort::SfIp & host_ip,uint16_t port,uint16_t protocol,SnortProtocolId snort_protocol_id,bool is_appid_service)209 void HostAttributesManager::update_service(const snort::SfIp& host_ip, uint16_t port,
210 uint16_t protocol, SnortProtocolId snort_protocol_id, bool is_appid_service)
211 {
212 if ( active_cache )
213 {
214 bool created = false;
215 HostAttributesEntry host = active_cache->find_else_create(host_ip, &created);
216 if ( host )
217 {
218 if ( created )
219 {
220 host_attribute_stats.dynamic_host_adds++;
221 }
222
223 bool updated = false;
224 if ( host->update_service(port, protocol, snort_protocol_id, updated, is_appid_service) )
225 {
226 if ( updated )
227 host_attribute_stats.dynamic_service_updates++;
228 else
229 host_attribute_stats.dynamic_service_adds++;
230 }
231 else
232 host_attribute_stats.service_list_overflows++;
233 }
234 }
235 }
236
clear_appid_services()237 void HostAttributesManager::clear_appid_services()
238 {
239 if ( active_cache )
240 {
241 auto hosts = active_cache->get_all_data();
242 for ( auto& h : hosts )
243 h.second->clear_appid_services();
244 }
245 }
246
get_num_host_entries()247 int32_t HostAttributesManager::get_num_host_entries()
248 {
249 if ( active_cache )
250 return active_cache->size();
251
252 return -1;
253 }
254
get_pegs()255 const PegInfo* HostAttributesManager::get_pegs()
256 { return (const PegInfo*)&host_attribute_pegs; }
257
get_peg_counts()258 PegCount* HostAttributesManager::get_peg_counts()
259 {
260 if ( active_cache )
261 {
262 LruCacheSharedStats* cache_stats = (LruCacheSharedStats*) active_cache->get_counts();
263 host_attribute_stats.hosts_pruned = cache_stats->alloc_prunes;
264 host_attribute_stats.total_hosts = active_cache->size();
265 }
266
267 return (PegCount*)&host_attribute_stats;
268 }
269
270