1 //--------------------------------------------------------------------------
2 // Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
3 //
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.
8 //
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.
13 //
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 
19 // host_tracker.h author Steve Chew <stechew@cisco.com>
20 
21 #ifndef HOST_TRACKER_H
22 #define HOST_TRACKER_H
23 
24 // The HostTracker class holds information known about a host (may be from
25 // configuration or dynamic discovery).  It provides a thread-safe API to
26 // set/get the host data.
27 
28 #include <cstring>
29 #include <mutex>
30 #include <list>
31 #include <set>
32 #include <unordered_set>
33 #include <vector>
34 
35 #include "framework/counts.h"
36 #include "host_cache_allocator.h"
37 #include "main/snort_types.h"
38 #include "main/thread.h"
39 #include "network_inspectors/appid/application_ids.h"
40 #include "protocols/protocol_ids.h"
41 #include "protocols/vlan.h"
42 #include "time/packet_time.h"
43 
44 struct HostTrackerStats
45 {
46     PegCount service_adds;
47     PegCount service_finds;
48 };
49 
50 extern THREAD_LOCAL struct HostTrackerStats host_tracker_stats;
51 
52 class RNAFlow;
53 
54 namespace snort
55 {
56 #define INFO_SIZE 32
57 #define MAC_SIZE 6
58 extern const uint8_t zero_mac[MAC_SIZE];
59 
60 struct HostMac
61 {
HostMacHostMac62     HostMac() : ttl(0), primary(0), last_seen(0)
63     { memset(mac, 0, MAC_SIZE); }
64 
HostMacHostMac65     HostMac(uint8_t p_ttl, const uint8_t* p_mac, uint8_t p_primary, uint32_t p_last_seen)
66         : ttl(p_ttl), primary(p_primary), last_seen (p_last_seen) { memcpy(mac, p_mac, MAC_SIZE); }
67 
68     // the type and order below should match logger's serialization
69     uint8_t ttl;
70     uint8_t mac[MAC_SIZE];
71     uint8_t primary;
72     uint32_t last_seen;
73 };
74 
75 struct HostApplicationInfo
76 {
77     HostApplicationInfo() = default;
78     HostApplicationInfo(const char *ver, const char *ven);
79     char vendor[INFO_SIZE] = { '\0' };
80     char version[INFO_SIZE] = { '\0' };
81 
82     friend class HostTracker;
83 private:
84     bool visibility = true;
85 };
86 
87 typedef HostCacheAllocIp<HostApplicationInfo> HostAppInfoAllocator;
88 typedef std::pair<AppId, bool> Payload_t;
89 typedef std::vector<Payload_t, HostCacheAllocIp<Payload_t>> PayloadVector;
90 
91 struct HostApplication
92 {
93     HostApplication() = default;
94     HostApplication(Port pt, IpProtocol pr, AppId ap, bool in, uint32_t ht = 0, uint32_t ls = 0,
portHostApplication95         bool banner = false) : port(pt), proto(pr), appid(ap), inferred_appid(in), hits(ht),
96         last_seen(ls), banner_updated(banner) { }
HostApplicationHostApplication97     HostApplication(const HostApplication& ha): port(ha.port), proto(ha.proto), appid(ha.appid),
98         inferred_appid(ha.inferred_appid), hits(ha.hits), last_seen(ha.last_seen),
99         num_visible_payloads(ha.num_visible_payloads), info(ha.info), payloads(ha.payloads),
100         visibility(ha.visibility) { }
101 
102     HostApplication& operator=(const HostApplication& ha)
103     {
104         port = ha.port;
105         proto = ha.proto;
106         appid = ha.appid;
107         inferred_appid = ha.inferred_appid;
108         hits = ha.hits;
109         last_seen = ha.last_seen;
110         info = ha.info;
111         payloads = ha.payloads;
112         visibility = ha.visibility;
113         banner_updated = ha.banner_updated;
114         num_visible_payloads = ha.num_visible_payloads;
115         return *this;
116     }
117 
118     Port port = 0;
119     IpProtocol proto;
120     AppId appid = APP_ID_NONE;
121     bool inferred_appid = false;
122     uint32_t hits = 0;
123     uint32_t last_seen = 0;
124     char user[INFO_SIZE] = { '\0' };
125     uint8_t user_login = 0;
126     bool banner_updated = false;
127     size_t num_visible_payloads = 0;
128 
129     std::vector<HostApplicationInfo, HostAppInfoAllocator> info;
130     PayloadVector payloads;
131 
132     friend class HostTracker;
133 
134 // visibility is public in UT only, to avoid extra lock/unlock funcs used only by UT
135 #ifndef UNIT_TEST
136 private:
137 #endif
138     bool visibility = true;
139 
140 };
141 
142 struct HostClient
143 {
144     HostClient() = default;
145     HostClient(AppId clientid, const char *ver, AppId ser);
146     AppId id;
147     char version[INFO_SIZE] = { '\0' };
148     AppId service;
149     PayloadVector payloads;
150     size_t num_visible_payloads = 0;
151 
152     bool operator==(const HostClient& c) const
153     {
154         return id == c.id and service == c.service;
155     }
156 
157     friend class HostTracker;
158 
159 private:
160     bool visibility = true;
161 };
162 
163 struct DeviceFingerprint
164 {
165     DeviceFingerprint(uint32_t id, uint32_t type, bool jb, const char* dev);
166     uint32_t fpid;
167     uint32_t fp_type;
168     bool jail_broken;
169     char device[INFO_SIZE] = { '\0' };
170 };
171 
172 enum HostType : std::uint32_t
173 {
174     HOST_TYPE_HOST = 0,
175     HOST_TYPE_ROUTER,
176     HOST_TYPE_BRIDGE,
177     HOST_TYPE_NAT,
178     HOST_TYPE_LB
179 };
180 
181 class HostMac_t : public HostMac
182 {
183 public:
HostMac_t(uint8_t p_ttl,const uint8_t * p_mac,uint8_t p_primary,uint32_t p_last_seen)184     HostMac_t(uint8_t p_ttl, const uint8_t* p_mac, uint8_t p_primary, uint32_t p_last_seen)
185         : HostMac(p_ttl, p_mac, p_primary, p_last_seen) {}
186 
187     HostMac_t& operator=(const HostMac_t& hm)
188     {
189         ttl = hm.ttl;
190         primary = hm.primary;
191         last_seen = hm.last_seen;
192         visibility = hm.visibility;
193         memcpy(mac, hm.mac, MAC_SIZE);
194         return *this;
195     }
196 
197     bool visibility = true;
198 };
199 
200 #define MIN_BOOT_TIME    10
201 #define MIN_TTL_DIFF     16
202 
203 typedef HostCacheAllocIp<HostApplication> HostAppAllocator;
204 typedef HostCacheAllocIp<HostClient> HostClientAllocator;
205 typedef HostCacheAllocIp<DeviceFingerprint> HostDeviceFpAllocator;
206 
207 class SO_PUBLIC HostTracker
208 {
209 public:
210 
211     typedef std::pair<uint16_t, bool> NetProto_t;
212     typedef std::pair<uint8_t, bool> XProto_t;
213 
214     HostTracker();
215 
216     void update_last_seen();
get_last_seen()217     uint32_t get_last_seen() const
218     {
219         std::lock_guard<std::mutex> lck(host_tracker_lock);
220         return last_seen;
221     }
222 
223     void update_last_event(uint32_t time = 0);
get_last_event()224     uint32_t get_last_event() const
225     {
226         std::lock_guard<std::mutex> lck(host_tracker_lock);
227         return last_event;
228     }
229 
get_network_protos()230     std::vector<uint16_t> get_network_protos()
231     {
232         std::vector<uint16_t> out_protos;
233         std::lock_guard<std::mutex> lck(host_tracker_lock);
234         for (const auto& proto : network_protos)
235             if ( proto.second )
236                 out_protos.emplace_back(proto.first);
237         return out_protos;
238     }
239 
get_xport_protos()240     std::vector<uint16_t> get_xport_protos()
241     {
242         std::vector<uint16_t> out_protos;
243         std::lock_guard<std::mutex> lck(host_tracker_lock);
244         for (const auto& proto : xport_protos)
245             if ( proto.second )
246                 out_protos.emplace_back(proto.first);
247         return out_protos;
248     }
249 
set_host_type(HostType rht)250     void set_host_type(HostType rht)
251     {
252         std::lock_guard<std::mutex> lck(host_tracker_lock);
253         host_type = rht;
254     }
255 
get_host_type()256     HostType get_host_type() const
257     {
258         std::lock_guard<std::mutex> lck(host_tracker_lock);
259         return host_type;
260     }
261 
get_hops()262     uint8_t get_hops()
263     {
264         std::lock_guard<std::mutex> lck(host_tracker_lock);
265         return hops;
266     }
267 
update_hops(uint8_t h)268     void update_hops(uint8_t h)
269     {
270         std::lock_guard<std::mutex> lck(host_tracker_lock);
271         hops = h;
272     }
273 
274     bool add_client_payload(HostClient&, AppId, size_t);
275 
276     // Returns true if a new mac entry is added, false otherwise
277     bool add_mac(const uint8_t* mac, uint8_t ttl, uint8_t primary);
278 
279     // Returns true if a mac entry TTL is updated and decreased, false otherwise
280     bool update_mac_ttl(const uint8_t* mac, uint8_t new_ttl);
281 
282     // Returns true if we changed primary (false->true), false otherwise
283     bool make_primary(const uint8_t* mac);
284 
285     // Returns true if a new payload entry added, false otherwise
286     bool add_payload(HostApplication&, Port, IpProtocol, const AppId payload,
287         const AppId service, size_t max_payloads);
288 
289     // Returns true after resetting hops if there is a primary mac
290     bool reset_hops_if_primary();
291 
292     // Returns true and copy of the matching HostMac, false if no match...
293     bool get_hostmac(const uint8_t* mac, HostMac& hm);
294 
295     const uint8_t* get_last_seen_mac(uint8_t*);
296 
297     void update_vlan(uint16_t vth_pri_cfi_vlan, uint16_t vth_proto);
298     bool has_same_vlan(uint16_t);
299     void get_vlan_details(uint8_t& cfi, uint8_t& priority, uint16_t& vid);
300 
301     // The caller owns and deletes the copied list of mac addresses
302     void copy_data(uint8_t& p_hops, uint32_t& p_last_seen, std::list<HostMac>*& p_macs);
303 
304     bool add_network_proto(const uint16_t type);
305     bool add_xport_proto(const uint8_t type);
306 
307     // Appid may not be identified always. Inferred means dynamic/runtime
308     // appid detected from one flow to another flow such as BitTorrent.
309     bool add_service(Port, IpProtocol,
310         AppId appid = APP_ID_NONE, bool inferred_appid = false, bool* added = nullptr);
311     bool add_service(const HostApplication&, bool* added = nullptr);
312     void clear_service(HostApplication&);
313     void update_service_port(HostApplication&, Port);
314     void update_service_proto(HostApplication&, IpProtocol);
315 
316     AppId get_appid(Port, IpProtocol, bool inferred_only = false,
317         bool allow_port_wildcard = false);
318 
319     size_t get_service_count();
320 
321     HostApplication add_service(Port, IpProtocol, uint32_t, bool&, AppId appid = APP_ID_NONE);
322 
323     void update_service(const HostApplication&);
324     bool update_service_info(HostApplication&, const char* vendor, const char* version,
325         uint16_t max_info);
326     bool update_service_banner(Port, IpProtocol);
327     bool update_service_user(Port, IpProtocol, const char* username, uint32_t lseen,
328         uint16_t max_services, bool success);
329     void remove_inferred_services();
330 
331     size_t get_client_count();
332     HostClient find_or_add_client(AppId id, const char* version, AppId service,
333         bool& is_new);
334     bool add_tcp_fingerprint(uint32_t fpid);
335     bool add_ua_fingerprint(uint32_t fpid, uint32_t fp_type, bool jail_broken,
336         const char* device_info, uint8_t max_devices);
337     bool add_udp_fingerprint(uint32_t fpid);
338     bool add_smb_fingerprint(uint32_t fpid);
339 
340     bool add_cpe_os_hash(uint32_t hash);
341 
342     //  This should be updated whenever HostTracker data members are changed
343     void stringify(std::string& str);
344 
get_ip_ttl()345     uint8_t get_ip_ttl() const
346     {
347         std::lock_guard<std::mutex> lck(host_tracker_lock);
348         return ip_ttl;
349     }
350 
set_ip_ttl(uint8_t ttl)351     void set_ip_ttl(uint8_t ttl)
352     {
353         std::lock_guard<std::mutex> lck(host_tracker_lock);
354         ip_ttl = ttl;
355     }
356 
get_nat_count_start()357     uint32_t get_nat_count_start() const
358     {
359         std::lock_guard<std::mutex> lck(host_tracker_lock);
360         return nat_count_start;
361     }
362 
set_nat_count_start(uint32_t natCountStart)363     void set_nat_count_start(uint32_t natCountStart)
364     {
365         std::lock_guard<std::mutex> lck(host_tracker_lock);
366         nat_count_start = natCountStart;
367     }
368 
get_nat_count()369     uint32_t get_nat_count() const
370     {
371         std::lock_guard<std::mutex> lck(host_tracker_lock);
372         return nat_count;
373     }
374 
375     void set_nat_count(uint32_t v = 0)
376     {
377         std::lock_guard<std::mutex> lck(host_tracker_lock);
378         nat_count = v;
379     }
380 
inc_nat_count()381     uint32_t inc_nat_count()
382     {
383         std::lock_guard<std::mutex> lck(host_tracker_lock);
384         return ++nat_count;
385     }
386 
387     bool set_netbios_name(const char*);
388 
389     bool set_visibility(bool v = true);
390 
391     bool is_visible() const;
392 
393     // the control delete commands do not actually remove objects from
394     // the host tracker, but just mark them as invisible, until rediscovered.
395     bool set_network_proto_visibility(uint16_t proto, bool v = true);
396     bool set_xproto_visibility(uint8_t proto, bool v = true);
397     bool set_service_visibility(Port, IpProtocol, bool v = true);
398     bool set_client_visibility(const HostClient&, bool v = true);
399 
400 #ifdef UNIT_TEST
401     // Caller is responsible for checking visibility
get_services()402     std::vector<HostApplication, HostAppAllocator> get_services()
403     {
404         std::lock_guard<std::mutex> lck(host_tracker_lock);
405         return services;
406     }
407 
408     // Caller is responsible for checking visibility
get_clients()409     std::vector<HostClient, HostClientAllocator> get_clients()
410     {
411         std::lock_guard<std::mutex> lck(host_tracker_lock);
412         return clients;
413     }
414 #endif
415 
416     void add_flow(RNAFlow*);
417     void remove_flows();
418     void remove_flow(RNAFlow*);
419 
420 private:
421 
422     mutable std::mutex host_tracker_lock; // ensure that updates to a shared object are safe
423     mutable std::mutex flows_lock;        // protect the flows set separately
424     uint8_t hops;                 // hops from the snort inspector, e.g., zero for ARP
425     uint32_t last_seen;           // the last time this host was seen
426     uint32_t last_event;          // the last time an event was generated
427 
428     // list guarantees iterator validity on insertion
429     std::list<HostMac_t, HostCacheAllocIp<HostMac_t>> macs;
430     std::vector<NetProto_t, HostCacheAllocIp<NetProto_t>> network_protos;
431     std::vector<XProto_t, HostCacheAllocIp<XProto_t>> xport_protos;
432     std::vector<HostApplication, HostAppAllocator> services;
433     std::vector<HostClient, HostClientAllocator> clients;
434     std::set<uint32_t, std::less<uint32_t>, HostCacheAllocIp<uint32_t>> tcp_fpids;
435     std::set<uint32_t, std::less<uint32_t>, HostCacheAllocIp<uint32_t>> udp_fpids;
436     std::set<uint32_t, std::less<uint32_t>, HostCacheAllocIp<uint32_t>> smb_fpids;
437     std::set<uint32_t, std::less<uint32_t>, HostCacheAllocIp<uint32_t>> cpe_fpids;
438     std::vector<DeviceFingerprint, HostDeviceFpAllocator> ua_fps;
439     std::string netbios_name;
440 
441     // flows that we belong to
442     std::unordered_set<RNAFlow*> flows;
443 
444     bool vlan_tag_present = false;
445     vlan::VlanTagHdr vlan_tag;
446     HostType host_type = HOST_TYPE_HOST;
447     uint8_t ip_ttl = 0;
448     uint32_t nat_count = 0;
449     uint32_t nat_count_start;     // the time nat counting starts for this host
450 
451     size_t visibility;
452 
453     uint32_t num_visible_services = 0;
454     uint32_t num_visible_clients = 0;
455     uint32_t num_visible_macs = 0;
456 
457     // These three do not lock independently; they are used by payload discovery and called
458     // from add_payload(HostApplication&, Port, IpProtocol, AppId, AppId, size_t); where the
459     // lock is actually obtained
460     bool add_payload_no_lock(const AppId, HostApplication*, size_t);
461     HostApplication* find_service_no_lock(Port, IpProtocol, AppId);
462     void update_ha_no_lock(HostApplication& dst, HostApplication& src);
463 
464     HostApplication* find_and_add_service_no_lock(Port, IpProtocol, uint32_t lseen,
465         bool& is_new, AppId, uint16_t max_services = 0);
466 
467     // Sets all payloads visible or invisible
468     void set_payload_visibility_no_lock(PayloadVector& pv, bool v, size_t& num_vis);
469 
470     // Hide / delete the constructor from the outside world. We don't want to
471     // have zombie host trackers, i.e. host tracker objects that live outside
472     // the host cache.
473     HostTracker( const HostTracker& ) = delete;
474     HostTracker( const HostTracker&& ) = delete;
475 
476     HostTracker& operator=( const HostTracker& ) = delete;
477     HostTracker& operator=( const HostTracker&& ) = delete;
478 
479     // Only the host cache can create them ...
480     template<class Key, class Value, class Hash>
481     friend class LruCacheShared;
482 
483     // ... and some unit tests. See Utest.h and UtestMacros.h in cpputest.
484     friend class TEST_host_tracker_add_find_service_test_Test;
485     friend class TEST_host_tracker_stringify_Test;
486 };
487 } // namespace snort
488 #endif
489