1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-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.cc author Steve Chew <stechew@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <algorithm>
26
27 #include "flow/flow.h"
28 #include "network_inspectors/rna/rna_flow.h"
29 #include "utils/util.h"
30
31 #include "host_cache.h"
32 #include "host_cache_allocator.cc"
33 #include "host_tracker.h"
34
35 using namespace snort;
36 using namespace std;
37
38 #define USER_LOGIN_SUCCESS 1
39 #define USER_LOGIN_FAILURE 2
40
41 THREAD_LOCAL struct HostTrackerStats host_tracker_stats;
42
43 const uint8_t snort::zero_mac[MAC_SIZE] = {0, 0, 0, 0, 0, 0};
44
45
HostTracker()46 HostTracker::HostTracker() : hops(-1)
47 {
48 last_seen = nat_count_start = (uint32_t) packet_time();
49 last_event = -1;
50 visibility = host_cache.get_valid_id();
51 }
52
update_last_seen()53 void HostTracker::update_last_seen()
54 {
55 lock_guard<mutex> lck(host_tracker_lock);
56 last_seen = (uint32_t) packet_time();
57 }
58
update_last_event(uint32_t time)59 void HostTracker::update_last_event(uint32_t time)
60 {
61 lock_guard<mutex> lck(host_tracker_lock);
62 last_event = time ? time : last_seen;
63 }
64
add_network_proto(const uint16_t type)65 bool HostTracker::add_network_proto(const uint16_t type)
66 {
67 lock_guard<mutex> lck(host_tracker_lock);
68
69 for ( auto& proto : network_protos )
70 {
71 if ( proto.first == type )
72 {
73 if ( proto.second )
74 return false;
75 else
76 {
77 proto.second = true;
78 return true;
79 }
80 }
81 }
82
83 network_protos.emplace_back(type, true);
84 return true;
85 }
86
add_xport_proto(const uint8_t type)87 bool HostTracker::add_xport_proto(const uint8_t type)
88 {
89 lock_guard<mutex> lck(host_tracker_lock);
90
91 for ( auto& proto : xport_protos )
92 {
93 if ( proto.first == type )
94 {
95 if ( proto.second )
96 return false;
97 else
98 {
99 proto.second = true;
100 return true;
101 }
102 }
103 }
104
105 xport_protos.emplace_back(type, true);
106 return true;
107 }
108
add_mac(const uint8_t * mac,uint8_t ttl,uint8_t primary)109 bool HostTracker::add_mac(const uint8_t* mac, uint8_t ttl, uint8_t primary)
110 {
111 if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
112 return false;
113
114 HostMac_t* invisible_swap_candidate = nullptr;
115 lock_guard<mutex> lck(host_tracker_lock);
116
117 for ( auto& hm_t : macs )
118 {
119 if ( !memcmp(mac, hm_t.mac, MAC_SIZE) )
120 {
121 if ( hm_t.visibility )
122 {
123 return false;
124 }
125
126 hm_t.visibility = true;
127 hm_t.last_seen = last_seen;
128 num_visible_macs++;
129 return true;
130 }
131
132 if ( !invisible_swap_candidate and !hm_t.visibility )
133 {
134 invisible_swap_candidate = &hm_t;
135 break;
136 }
137 }
138
139 if ( invisible_swap_candidate )
140 {
141 memcpy(invisible_swap_candidate->mac, mac, MAC_SIZE);
142 invisible_swap_candidate->ttl = ttl;
143 invisible_swap_candidate->primary = primary;
144 invisible_swap_candidate->visibility = true;
145 invisible_swap_candidate->last_seen = last_seen;
146 num_visible_macs++;
147 return true;
148 }
149
150 macs.emplace_back(ttl, mac, primary, last_seen);
151 num_visible_macs++;
152
153 return true;
154 }
155
add_payload_no_lock(const AppId pld,HostApplication * ha,size_t max_payloads)156 bool HostTracker::add_payload_no_lock(const AppId pld, HostApplication* ha, size_t max_payloads)
157 {
158 Payload_t* invisible_swap_candidate = nullptr;
159
160 for ( auto& p : ha->payloads )
161 {
162 if ( p.first == pld )
163 {
164 if ( p.second )
165 {
166 return false;
167 }
168 else
169 {
170 p.second = true;
171 ha->num_visible_payloads++;
172 return true;
173 }
174 }
175
176 if ( !invisible_swap_candidate and !p.second )
177 invisible_swap_candidate = &p;
178 }
179
180 if ( invisible_swap_candidate )
181 {
182 invisible_swap_candidate->first = pld;
183 invisible_swap_candidate->second = true;
184 ha->num_visible_payloads++;
185 return true;
186 }
187
188 if ( ha->payloads.size() >= max_payloads )
189 return false;
190
191 ha->payloads.emplace_back(pld, true);
192 ha->num_visible_payloads++;
193
194 return true;
195 }
196
get_hostmac(const uint8_t * mac,HostMac & hm)197 bool HostTracker::get_hostmac(const uint8_t* mac, HostMac& hm)
198 {
199 if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
200 return false;
201
202 lock_guard<mutex> lck(host_tracker_lock);
203
204 for ( auto& ahm : macs )
205 if ( !memcmp(mac, ahm.mac, MAC_SIZE) )
206 {
207 if ( !ahm.visibility )
208 return false;
209
210 hm = static_cast<HostMac>(ahm);
211 return true;
212 }
213
214 return false;
215 }
216
get_last_seen_mac(uint8_t * mac_addr)217 const uint8_t* HostTracker::get_last_seen_mac(uint8_t* mac_addr)
218 {
219 lock_guard<mutex> lck(host_tracker_lock);
220 const HostMac_t* max_hm = nullptr;
221
222 for ( const auto& hm : macs )
223 if ( !max_hm or max_hm->last_seen < hm.last_seen )
224 if ( hm.visibility )
225 max_hm = &hm;
226
227 if ( max_hm )
228 {
229 memcpy(mac_addr, max_hm->mac, MAC_SIZE);
230 return mac_addr;
231 }
232
233 return zero_mac;
234 }
235
update_mac_ttl(const uint8_t * mac,uint8_t new_ttl)236 bool HostTracker::update_mac_ttl(const uint8_t* mac, uint8_t new_ttl)
237 {
238 if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
239 return false;
240
241 lock_guard<mutex> lck(host_tracker_lock);
242
243 for ( auto& hm : macs )
244 if ( !memcmp(mac, hm.mac, MAC_SIZE) )
245 {
246 if ( hm.ttl < new_ttl and hm.visibility )
247 {
248 hm.ttl = new_ttl;
249 return true;
250 }
251
252 return false;
253 }
254
255 return false;
256 }
257
make_primary(const uint8_t * mac)258 bool HostTracker::make_primary(const uint8_t* mac)
259 {
260 if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
261 return false;
262
263 HostMac_t* hm = nullptr;
264
265 lock_guard<mutex> lck(host_tracker_lock);
266
267 for ( auto& hm_iter : macs )
268 if ( !memcmp(mac, hm_iter.mac, MAC_SIZE) )
269 {
270 if ( !hm_iter.visibility )
271 return false;
272
273 hm = &hm_iter;
274 break;
275 }
276
277 if ( !hm )
278 return false;
279
280 hm->last_seen = last_seen;
281 if ( !hm->primary )
282 {
283 hm->primary = true;
284 return true;
285 }
286
287 return false;
288 }
289
reset_hops_if_primary()290 bool HostTracker::reset_hops_if_primary()
291 {
292 lock_guard<mutex> lck(host_tracker_lock);
293
294 for ( auto& hm : macs )
295 if ( hm.primary and hm.visibility )
296 {
297 if ( !hops )
298 return false;
299 hops = 0;
300 return true;
301 }
302
303 return false;
304 }
305
update_vlan(uint16_t vth_pri_cfi_vlan,uint16_t vth_proto)306 void HostTracker::update_vlan(uint16_t vth_pri_cfi_vlan, uint16_t vth_proto)
307 {
308 lock_guard<mutex> lck(host_tracker_lock);
309 vlan_tag_present = true;
310 vlan_tag.vth_pri_cfi_vlan = vth_pri_cfi_vlan;
311 vlan_tag.vth_proto = vth_proto;
312 }
313
has_same_vlan(uint16_t pvlan)314 bool HostTracker::has_same_vlan(uint16_t pvlan)
315 {
316 lock_guard<mutex> lck(host_tracker_lock);
317 return vlan_tag_present and ( vlan_tag.vth_pri_cfi_vlan == pvlan );
318 }
319
get_vlan_details(uint8_t & cfi,uint8_t & priority,uint16_t & vid)320 void HostTracker::get_vlan_details(uint8_t& cfi, uint8_t& priority, uint16_t& vid)
321 {
322 lock_guard<mutex> lck(host_tracker_lock);
323 cfi = vlan_tag.cfi();
324 priority = vlan_tag.priority();
325 vid = vlan_tag.vid();
326 }
327
copy_data(uint8_t & p_hops,uint32_t & p_last_seen,list<HostMac> * & p_macs)328 void HostTracker::copy_data(uint8_t& p_hops, uint32_t& p_last_seen, list<HostMac>*& p_macs)
329 {
330 lock_guard<mutex> lck(host_tracker_lock);
331
332 p_hops = hops;
333 p_last_seen = last_seen;
334 if ( !macs.empty() )
335 p_macs = new list<HostMac>(macs.begin(), macs.end());
336 }
337
add_service(Port port,IpProtocol proto,AppId appid,bool inferred_appid,bool * added)338 bool HostTracker::add_service(Port port, IpProtocol proto, AppId appid, bool inferred_appid,
339 bool* added)
340 {
341 host_tracker_stats.service_adds++;
342 lock_guard<mutex> lck(host_tracker_lock);
343
344 for ( auto& s : services )
345 {
346 if ( s.port == port and s.proto == proto )
347 {
348 if ( s.appid != appid and appid != APP_ID_NONE )
349 {
350 s.appid = appid;
351 s.inferred_appid = inferred_appid;
352 if ( added )
353 *added = true;
354 }
355
356 if ( s.visibility == false )
357 {
358 if ( added )
359 *added = true;
360 s.visibility = true;
361 num_visible_services++;
362 }
363
364 return true;
365 }
366 }
367
368 services.emplace_back(port, proto, appid, inferred_appid);
369 num_visible_services++;
370 if ( added )
371 *added = true;
372
373 return true;
374 }
375
clear_service(HostApplication & ha)376 void HostTracker::clear_service(HostApplication& ha)
377 {
378 lock_guard<mutex> lck(host_tracker_lock);
379 ha.port = 0;
380 ha.proto = (IpProtocol) 0;
381 ha.appid = (AppId) 0;
382 ha.inferred_appid = false;
383 ha.hits = 0;
384 ha.last_seen = 0;
385 ha.payloads.clear();
386 ha.info.clear();
387 ha.banner_updated = false;
388 }
389
add_client_payload(HostClient & hc,AppId payload,size_t max_payloads)390 bool HostTracker::add_client_payload(HostClient& hc, AppId payload, size_t max_payloads)
391 {
392 Payload_t* invisible_swap_candidate = nullptr;
393 std::lock_guard<std::mutex> lck(host_tracker_lock);
394
395 for ( auto& client : clients )
396 if ( client.id == hc.id and client.service == hc.service )
397 {
398 for ( auto& pld : client.payloads )
399 {
400 if ( pld.first == payload )
401 {
402 if ( pld.second )
403 return false;
404
405 pld.second = true;
406 client.num_visible_payloads++;
407 hc.payloads = client.payloads;
408 strncpy(hc.version, client.version, INFO_SIZE);
409 return true;
410 }
411 if ( !invisible_swap_candidate and !pld.second )
412 invisible_swap_candidate = &pld;
413 }
414
415 if ( invisible_swap_candidate )
416 {
417 invisible_swap_candidate->second = true;
418 invisible_swap_candidate->first = payload;
419 client.num_visible_payloads++;
420 hc.payloads = client.payloads;
421 strncpy(hc.version, client.version, INFO_SIZE);
422 return true;
423 }
424
425 if ( client.payloads.size() >= max_payloads )
426 return false;
427
428 client.payloads.emplace_back(payload, true);
429 hc.payloads = client.payloads;
430 strncpy(hc.version, client.version, INFO_SIZE);
431 client.num_visible_payloads++;
432 return true;
433 }
434
435 return false;
436 }
437
add_service(const HostApplication & app,bool * added)438 bool HostTracker::add_service(const HostApplication& app, bool* added)
439 {
440 host_tracker_stats.service_adds++;
441 lock_guard<mutex> lck(host_tracker_lock);
442
443 for ( auto& s : services )
444 {
445 if ( s.port == app.port and s.proto == app.proto )
446 {
447 if ( s.appid != app.appid and app.appid != APP_ID_NONE )
448 {
449 s.appid = app.appid;
450 s.inferred_appid = app.inferred_appid;
451 if ( added )
452 *added = true;
453 }
454
455 if ( s.visibility == false )
456 {
457 if ( added )
458 *added = true;
459 s.visibility = true;
460 num_visible_services++;
461 }
462
463 return true;
464 }
465 }
466
467 services.emplace_back(app.port, app.proto, app.appid, app.inferred_appid);
468 num_visible_services++;
469 if ( added )
470 *added = true;
471
472 return true;
473 }
474
get_appid(Port port,IpProtocol proto,bool inferred_only,bool allow_port_wildcard)475 AppId HostTracker::get_appid(Port port, IpProtocol proto, bool inferred_only,
476 bool allow_port_wildcard)
477 {
478 host_tracker_stats.service_finds++;
479 lock_guard<mutex> lck(host_tracker_lock);
480
481 for ( const auto& s : services )
482 {
483 bool matched = (s.port == port and s.proto == proto and
484 (!inferred_only or s.inferred_appid == inferred_only));
485 if ( matched or ( allow_port_wildcard and s.inferred_appid ) )
486 return s.appid;
487 }
488
489 return APP_ID_NONE;
490 }
491
get_service_count()492 size_t HostTracker::get_service_count()
493 {
494 lock_guard<mutex> lck(host_tracker_lock);
495 return num_visible_services;
496 }
497
find_service_no_lock(Port port,IpProtocol proto,AppId appid)498 HostApplication* HostTracker::find_service_no_lock(Port port, IpProtocol proto, AppId appid)
499 {
500 for ( auto& s : services )
501 {
502 if ( s.port == port and s.proto == proto )
503 {
504 if ( s.visibility == false )
505 return nullptr;
506 if ( appid != APP_ID_NONE and s.appid == appid )
507 return &s;
508 }
509 }
510
511 return nullptr;
512 }
513
add_payload(HostApplication & local_ha,Port port,IpProtocol proto,AppId payload,AppId service,size_t max_payloads)514 bool HostTracker::add_payload(HostApplication& local_ha, Port port, IpProtocol proto, AppId payload,
515 AppId service, size_t max_payloads)
516 {
517 // This lock is responsible for find_service and add_payload
518 lock_guard<mutex> lck(host_tracker_lock);
519
520 auto ha = find_service_no_lock(port, proto, service);
521
522 if ( ha )
523 {
524 bool success = add_payload_no_lock(payload, ha, max_payloads);
525 local_ha = *ha;
526 local_ha.payloads = ha->payloads;
527 return success;
528 }
529
530 return false;
531 }
532
find_and_add_service_no_lock(Port port,IpProtocol proto,uint32_t lseen,bool & is_new,AppId appid,uint16_t max_services)533 HostApplication* HostTracker::find_and_add_service_no_lock(Port port, IpProtocol proto,
534 uint32_t lseen, bool& is_new, AppId appid, uint16_t max_services)
535 {
536 host_tracker_stats.service_finds++;
537 HostApplication *available = nullptr;
538
539 for ( auto& s : services )
540 {
541 if ( s.port == port and s.proto == proto )
542 {
543 if ( (appid != APP_ID_NONE and s.appid != appid) or !s.visibility )
544 {
545 s.appid = appid;
546 is_new = true;
547 s.hits = 1;
548 if ( !s.visibility )
549 {
550 s.visibility = true;
551 num_visible_services++;
552 }
553 else
554 s.hits = 0;
555 }
556 else if ( s.last_seen == 0 )
557 {
558 is_new = true;
559 s.hits = 1;
560 }
561 else
562 ++s.hits;
563
564 s.last_seen = lseen;
565
566 return &s;
567 }
568 else if ( !available and !s.visibility )
569 available = &s;
570 }
571
572 is_new = true;
573 host_tracker_stats.service_adds++;
574 num_visible_services++;
575 if ( available )
576 {
577 available->port = port;
578 available->proto = proto;
579 available->appid = appid;
580 available->hits = 1;
581 available->last_seen = lseen;
582 available->inferred_appid = false;
583 available->user[0] = '\0';
584 available->user_login = 0;
585 available->banner_updated = false;
586 available->visibility = true;
587 return available;
588 }
589
590 if ( max_services == 0 or num_visible_services < max_services )
591 {
592 services.emplace_back(port, proto, appid, false, 1, lseen);
593 return &services.back();
594 }
595 return nullptr;
596 }
597
add_service(Port port,IpProtocol proto,uint32_t lseen,bool & is_new,AppId appid)598 HostApplication HostTracker::add_service(Port port, IpProtocol proto, uint32_t lseen,
599 bool& is_new, AppId appid)
600 {
601 lock_guard<mutex> lck(host_tracker_lock);
602 HostApplication* ha = find_and_add_service_no_lock(port, proto, lseen, is_new, appid);
603 return *ha;
604 }
605
update_service(const HostApplication & ha)606 void HostTracker::update_service(const HostApplication& ha)
607 {
608 host_tracker_stats.service_finds++;
609 lock_guard<mutex> lck(host_tracker_lock);
610
611 for ( auto& s : services )
612 {
613 if ( s.port == ha.port and s.proto == ha.proto )
614 {
615 s.hits = ha.hits;
616 s.last_seen = ha.last_seen;
617 return;
618 }
619 }
620 }
621
update_service_port(HostApplication & app,Port port)622 void HostTracker::update_service_port(HostApplication& app, Port port)
623 {
624 lock_guard<mutex> lck(host_tracker_lock);
625 app.port = port;
626 }
627
update_service_proto(HostApplication & app,IpProtocol proto)628 void HostTracker::update_service_proto(HostApplication& app, IpProtocol proto)
629 {
630 lock_guard<mutex> lck(host_tracker_lock);
631 app.proto = proto;
632 }
633
update_ha_no_lock(HostApplication & dst,HostApplication & src)634 void HostTracker::update_ha_no_lock(HostApplication& dst, HostApplication& src)
635 {
636 if ( dst.appid == APP_ID_NONE )
637 dst.appid = src.appid;
638 else
639 src.appid = dst.appid;
640
641 for ( auto& i: src.info )
642 if ( i.visibility == true )
643 dst.info.emplace_back(i.version, i.vendor);
644
645 dst.hits = src.hits;
646 }
647
update_service_info(HostApplication & ha,const char * vendor,const char * version,uint16_t max_info)648 bool HostTracker::update_service_info(HostApplication& ha, const char* vendor,
649 const char* version, uint16_t max_info)
650 {
651 host_tracker_stats.service_finds++;
652 lock_guard<mutex> lck(host_tracker_lock);
653
654 for ( auto& s : services )
655 {
656 if ( s.port == ha.port and s.proto == ha.proto )
657 {
658 if ( s.visibility == false )
659 return false;
660
661 if ( !version and !vendor )
662 return true;
663
664 HostApplicationInfo* available = nullptr;
665 for ( auto& i : s.info )
666 {
667 if ( (version and !strncmp(version, i.version, INFO_SIZE-1)) and
668 (vendor and !strncmp(vendor, i.vendor, INFO_SIZE-1)) )
669 {
670 if ( i.visibility == false )
671 {
672 i.visibility = true; // rediscover it
673 update_ha_no_lock(ha, s);
674 return true;
675 }
676 return false;
677 }
678 else if ( !available and !i.visibility )
679 available = &i;
680 }
681
682 if ( available and (version or vendor) )
683 {
684 if ( version )
685 {
686 strncpy(available->version, version, INFO_SIZE);
687 available->version[INFO_SIZE-1]='\0';
688 }
689
690 if ( vendor )
691 {
692 strncpy(available->vendor, vendor, INFO_SIZE);
693 available->vendor[INFO_SIZE-1]='\0';
694 }
695
696 available->visibility = true;
697 }
698 else if ( s.info.size() < max_info )
699 s.info.emplace_back(version, vendor);
700 else
701 return false;
702
703 update_ha_no_lock(ha, s);
704 return true;
705 }
706 }
707 return false;
708 }
709
update_service_banner(Port port,IpProtocol proto)710 bool HostTracker::update_service_banner(Port port, IpProtocol proto)
711 {
712 host_tracker_stats.service_finds++;
713 lock_guard<mutex> lck(host_tracker_lock);
714 for ( auto& s : services )
715 {
716 if ( s.port == port and s.proto == proto )
717 {
718 if ( !s.visibility or s.banner_updated )
719 return false;
720
721 s.banner_updated = true;
722 return true;
723 }
724 }
725 return false;
726 }
727
update_service_user(Port port,IpProtocol proto,const char * user,uint32_t lseen,uint16_t max_services,bool success)728 bool HostTracker::update_service_user(Port port, IpProtocol proto, const char* user,
729 uint32_t lseen, uint16_t max_services, bool success)
730 {
731 host_tracker_stats.service_finds++;
732 bool is_new = false;
733 lock_guard<mutex> lck(host_tracker_lock);
734
735 // Appid notifies user events before service events, so use find or add service function.
736 HostApplication* ha = find_and_add_service_no_lock(port, proto, lseen, is_new, 0,
737 max_services);
738 if ( !ha or ha->visibility == false )
739 return false;
740
741 if ( user and strncmp(user, ha->user, INFO_SIZE-1) )
742 {
743 strncpy(ha->user, user, INFO_SIZE);
744 ha->user[INFO_SIZE-1] = '\0';
745 ha->user_login = success ? USER_LOGIN_SUCCESS : USER_LOGIN_FAILURE;
746 return true;
747 }
748
749 if ( success )
750 {
751 if ( ha->user_login & USER_LOGIN_SUCCESS )
752 return false;
753 ha->user_login |= USER_LOGIN_SUCCESS;
754 return true;
755 }
756 else
757 {
758 if ( ha->user_login & USER_LOGIN_FAILURE )
759 return false;
760 ha->user_login |= USER_LOGIN_FAILURE;
761 return true;
762 }
763 }
764
remove_inferred_services()765 void HostTracker::remove_inferred_services()
766 {
767 lock_guard<mutex> lck(host_tracker_lock);
768 for ( auto s = services.begin(); s != services.end(); )
769 {
770 if ( s->inferred_appid )
771 s = services.erase(s);
772 else
773 s++;
774 }
775 }
776
add_tcp_fingerprint(uint32_t fpid)777 bool HostTracker::add_tcp_fingerprint(uint32_t fpid)
778 {
779 lock_guard<mutex> lck(host_tracker_lock);
780 auto result = tcp_fpids.emplace(fpid);
781 return result.second;
782 }
783
add_udp_fingerprint(uint32_t fpid)784 bool HostTracker::add_udp_fingerprint(uint32_t fpid)
785 {
786 lock_guard<mutex> lck(host_tracker_lock);
787 auto result = udp_fpids.emplace(fpid);
788 return result.second;
789 }
790
set_netbios_name(const char * nb_name)791 bool HostTracker::set_netbios_name(const char* nb_name)
792 {
793 std::lock_guard<std::mutex> lck(host_tracker_lock);
794 if ( nb_name && netbios_name != nb_name )
795 {
796 netbios_name = nb_name;
797 return true;
798 }
799 else
800 return false;
801 }
802
add_smb_fingerprint(uint32_t fpid)803 bool HostTracker::add_smb_fingerprint(uint32_t fpid)
804 {
805 lock_guard<mutex> lck(host_tracker_lock);
806 auto result = smb_fpids.emplace(fpid);
807 return result.second;
808 }
809
add_cpe_os_hash(uint32_t hash)810 bool HostTracker::add_cpe_os_hash(uint32_t hash)
811 {
812 lock_guard<mutex> lck(host_tracker_lock);
813 auto result = cpe_fpids.emplace(hash);
814 return result.second;
815 }
816
set_visibility(bool v)817 bool HostTracker::set_visibility(bool v)
818 {
819 // get_valid_id may use its own lock, so get this outside our lock
820 size_t container_id = host_cache.get_valid_id();
821
822 std::lock_guard<std::mutex> lck(host_tracker_lock);
823 size_t old_visibility = visibility;
824
825 visibility = v ? container_id : HostCacheIp::invalid_id;
826
827 if ( old_visibility != visibility )
828 {
829 for ( auto& proto : network_protos )
830 proto.second = false;
831
832 for ( auto& proto : xport_protos )
833 proto.second = false;
834
835 for ( auto& mac_t : macs )
836 mac_t.visibility = false;
837
838 num_visible_macs = 0;
839
840 for ( auto& s : services )
841 {
842 s.visibility = false;
843 for ( auto& info : s.info )
844 info.visibility = false;
845 s.user[0] = '\0';
846 set_payload_visibility_no_lock(s.payloads, false, s.num_visible_payloads);
847 }
848 num_visible_services = 0;
849
850 for ( auto& c : clients )
851 {
852 c.visibility = false;
853 set_payload_visibility_no_lock(c.payloads, false, c.num_visible_payloads);
854 }
855 num_visible_clients = 0;
856
857 tcp_fpids.clear();
858 ua_fps.clear();
859 udp_fpids.clear();
860 smb_fpids.clear();
861 netbios_name.clear();
862 cpe_fpids.clear();
863 }
864
865 return old_visibility == visibility;
866 }
867
is_visible() const868 bool HostTracker::is_visible() const
869 {
870 std::lock_guard<std::mutex> lck(host_tracker_lock);
871 return visibility == host_cache.get_valid_id();
872 }
873
874
set_network_proto_visibility(uint16_t proto,bool v)875 bool HostTracker::set_network_proto_visibility(uint16_t proto, bool v)
876 {
877 std::lock_guard<std::mutex> lck(host_tracker_lock);
878 for ( auto& pp : network_protos )
879 {
880 if ( pp.first == proto )
881 {
882 pp.second = v;
883 return true;
884 }
885 }
886 return false;
887 }
888
set_xproto_visibility(uint8_t proto,bool v)889 bool HostTracker::set_xproto_visibility(uint8_t proto, bool v)
890 {
891 std::lock_guard<std::mutex> lck(host_tracker_lock);
892 for ( auto& pp : xport_protos )
893 {
894 if ( pp.first == proto )
895 {
896 pp.second = v;
897 return true;
898 }
899 }
900 return false;
901 }
902
set_payload_visibility_no_lock(PayloadVector & pv,bool v,size_t & num_vis)903 void HostTracker::set_payload_visibility_no_lock(PayloadVector& pv, bool v, size_t& num_vis)
904 {
905 for ( auto& p : pv )
906 {
907 if ( p.second != v )
908 {
909 p.second = v;
910 if ( v )
911 num_vis++;
912 else
913 num_vis--;
914 }
915 }
916 }
917
set_service_visibility(Port port,IpProtocol proto,bool v)918 bool HostTracker::set_service_visibility(Port port, IpProtocol proto, bool v)
919 {
920 std::lock_guard<std::mutex> lck(host_tracker_lock);
921 for ( auto& s : services )
922 {
923 if ( s.port == port and s.proto == proto )
924 {
925 if ( s.visibility == true and v == false )
926 {
927 assert(num_visible_services > 0);
928 num_visible_services--;
929 }
930 else if ( s.visibility == false and v == true )
931 num_visible_services++;
932
933 s.visibility = v;
934 if ( s.visibility == false )
935 {
936 for ( auto& info : s.info )
937 info.visibility = false;
938 s.user[0] = '\0';
939 s.banner_updated = false;
940 }
941
942 set_payload_visibility_no_lock(s.payloads, v, s.num_visible_payloads);
943 return true;
944 }
945 }
946 return false;
947 }
948
set_client_visibility(const HostClient & hc,bool v)949 bool HostTracker::set_client_visibility(const HostClient& hc, bool v)
950 {
951 std::lock_guard<std::mutex> lck(host_tracker_lock);
952 bool deleted = false;
953 for ( auto& c : clients )
954 {
955 if ( c == hc )
956 {
957 if ( c.visibility == true and v == false )
958 {
959 assert(num_visible_clients > 0 );
960 num_visible_clients--;
961 }
962 else if ( c.visibility == false and v == true )
963 num_visible_clients++;
964
965 c.visibility = v;
966 set_payload_visibility_no_lock(c.payloads, v, c.num_visible_payloads);
967 deleted = true;
968 }
969 }
970 return deleted;
971 }
972
DeviceFingerprint(uint32_t id,uint32_t type,bool jb,const char * dev)973 DeviceFingerprint::DeviceFingerprint(uint32_t id, uint32_t type, bool jb, const char* dev) :
974 fpid(id), fp_type(type), jail_broken(jb)
975 {
976 if ( dev )
977 {
978 strncpy(device, dev, INFO_SIZE);
979 device[INFO_SIZE-1] = '\0';
980 }
981 }
982
add_ua_fingerprint(uint32_t fpid,uint32_t fp_type,bool jail_broken,const char * device,uint8_t max_devices)983 bool HostTracker::add_ua_fingerprint(uint32_t fpid, uint32_t fp_type, bool jail_broken,
984 const char* device, uint8_t max_devices)
985 {
986 lock_guard<mutex> lck(host_tracker_lock);
987
988 int count = 0;
989 for ( const auto& fp : ua_fps )
990 {
991 if ( fpid != fp.fpid or fp_type != fp.fp_type )
992 continue;
993 ++count; // only count same fpid with different device information
994 if ( count >= max_devices )
995 return false;
996 if ( jail_broken == fp.jail_broken and ( ( !device and fp.device[0] == '\0') or
997 ( device and strncmp(fp.device, device, INFO_SIZE) == 0) ) )
998 return false;
999 }
1000
1001 ua_fps.emplace_back(fpid, fp_type, jail_broken, device);
1002 return true;
1003 }
1004
get_client_count()1005 size_t HostTracker::get_client_count()
1006 {
1007 lock_guard<mutex> lck(host_tracker_lock);
1008 return num_visible_clients;
1009 }
1010
HostClient(AppId clientid,const char * ver,AppId ser)1011 HostClient::HostClient(AppId clientid, const char *ver, AppId ser) :
1012 id(clientid), service(ser)
1013 {
1014 if ( ver )
1015 {
1016 strncpy(version, ver, INFO_SIZE);
1017 version[INFO_SIZE-1] = '\0';
1018 }
1019 }
1020
find_or_add_client(AppId id,const char * version,AppId service,bool & is_new)1021 HostClient HostTracker::find_or_add_client(AppId id, const char* version, AppId service,
1022 bool& is_new)
1023 {
1024 lock_guard<mutex> lck(host_tracker_lock);
1025 HostClient* available = nullptr;
1026 for ( auto& c : clients )
1027 {
1028 if ( c.id != APP_ID_NONE and c.id == id and c.service == service
1029 and ((c.version[0] == '\0' and !version) or
1030 (version and strncmp(c.version, version, INFO_SIZE-1) == 0)) )
1031 {
1032 if ( c.visibility == false )
1033 {
1034 is_new = true;
1035 c.visibility = true;
1036 num_visible_clients++;
1037 }
1038
1039 return c;
1040 }
1041 else if ( !available and !c.visibility )
1042 available = &c;
1043 }
1044
1045 is_new = true;
1046 num_visible_clients++;
1047 if ( available )
1048 {
1049 available->id = id;
1050 available->service = service;
1051 available->visibility = true;
1052 if ( version )
1053 {
1054 strncpy(available->version, version, INFO_SIZE);
1055 available->version[INFO_SIZE-1] = '\0';
1056 }
1057 return *available;
1058 }
1059
1060 clients.emplace_back(id, version, service);
1061 return clients.back();
1062 }
1063
add_flow(RNAFlow * fd)1064 void HostTracker::add_flow(RNAFlow* fd)
1065 {
1066 lock_guard<mutex> lck(flows_lock);
1067 flows.insert(fd);
1068 }
1069
remove_flow(RNAFlow * fd)1070 void HostTracker::remove_flow(RNAFlow* fd)
1071 {
1072 lock_guard<mutex> lck(flows_lock);
1073 flows.erase(fd);
1074 }
1075
remove_flows()1076 void HostTracker::remove_flows()
1077 {
1078 // To lock, or not to lock? That is the question!
1079 //
1080 // The only way we get here is from LRU::update(), called by the allocator.
1081 // That is, we only get here from a HT::add_<> operation. All of those
1082 // operations lock the HT, so the HT is already locked when we get here.
1083 // Also, none of those operations modify the HT::flows set. So we should
1084 // not lock the HT (because we'd cause a deadlock), nor do we need to
1085 // (because there's no contention on HT::flows from those adds).
1086 //
1087 // However, this HT could be part of a different rna flow, which could
1088 // go out of existence exactly at the time when this thread modifies
1089 // the HT::flows set. The rna flow destructor calls on this
1090 // HT::remove_flow(), which does modify HT::flows. The for loop itself
1091 // does not modify the HT::flows set, but flows.clear() does - whether
1092 // or not we call it here explicitly. We, therefore, need to protect the
1093 // HT::flows() array with a lock on this host_tracker_lock.
1094 //
1095 // We have identified two situations with opposite requirements:
1096 // one requires locking, the other requires not locking.
1097 //
1098 // Now, note that the thread contention is not on the host tracker itself,
1099 // but on the HT::flows set. This means we may not lock the HT here,
1100 // to avoid the deadlock from the first case, but we SHOULD lock on
1101 // a different mutex to protect the HT::flows set.
1102 lock_guard<mutex> lck(flows_lock);
1103 for ( auto& rna_flow : flows )
1104 {
1105 rna_flow->clear_ht(*this);
1106 }
1107 flows.clear();
1108 }
1109
HostApplicationInfo(const char * ver,const char * ven)1110 HostApplicationInfo::HostApplicationInfo(const char *ver, const char *ven)
1111 {
1112 if ( ver )
1113 {
1114 strncpy(version, ver, INFO_SIZE);
1115 version[INFO_SIZE-1] = '\0';
1116 }
1117 if ( ven )
1118 {
1119 strncpy(vendor, ven, INFO_SIZE);
1120 vendor[INFO_SIZE-1] = '\0';
1121 }
1122 }
1123
to_time_string(uint32_t p_time)1124 static inline string to_time_string(uint32_t p_time)
1125 {
1126 time_t raw_time = (time_t) p_time;
1127 struct tm* timeinfo = gmtime(&raw_time);
1128 char buffer[30];
1129 strftime(buffer, 30, "%F %T", timeinfo);
1130 return buffer;
1131 }
1132
to_mac_string(const uint8_t * mac)1133 static inline string to_mac_string(const uint8_t* mac)
1134 {
1135 char mac_addr[18];
1136 snprintf(mac_addr, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
1137 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1138 return mac_addr;
1139 }
1140
1141 static std::vector<std::string> host_types = { "Host", "Router", "Bridge", "NAT", "Load Balancer" };
1142
to_host_type_string(HostType type)1143 static inline string& to_host_type_string(HostType type)
1144 {
1145 return host_types[type];
1146 }
1147
stringify(string & str)1148 void HostTracker::stringify(string& str)
1149 {
1150 lock_guard<mutex> lck(host_tracker_lock);
1151
1152 str += "\n type: " + to_host_type_string(host_type) + ", ttl: " + to_string(ip_ttl)
1153 + ", hops: " + to_string(hops) + ", time: " + to_time_string(last_seen);
1154
1155 if ( !macs.empty() )
1156 {
1157 str += "\nmacs size: " + to_string(num_visible_macs);
1158 for ( const auto& m : macs )
1159 {
1160 if ( m.visibility )
1161 {
1162 str += "\n mac: " + to_mac_string(m.mac)
1163 + ", ttl: " + to_string(m.ttl)
1164 + ", primary: " + to_string(m.primary)
1165 + ", time: " + to_time_string(m.last_seen);
1166 }
1167 }
1168 }
1169
1170 if ( num_visible_services > 0 )
1171 {
1172 str += "\nservices size: " + to_string(num_visible_services);
1173
1174 for ( const auto& s : services )
1175 {
1176 if ( s.visibility == false )
1177 continue;
1178
1179 str += "\n port: " + to_string(s.port)
1180 + ", proto: " + to_string((uint8_t) s.proto);
1181 if ( s.appid != APP_ID_NONE )
1182 {
1183 str += ", appid: " + to_string(s.appid);
1184 if ( s.inferred_appid )
1185 str += ", inferred";
1186 }
1187
1188 if ( !s.info.empty() )
1189 for ( const auto& i : s.info )
1190 {
1191 if ( i.visibility == false )
1192 continue;
1193
1194 if ( i.vendor[0] != '\0' )
1195 str += ", vendor: " + string(i.vendor);
1196 if ( i.version[0] != '\0' )
1197 str += ", version: " + string(i.version);
1198 }
1199
1200 auto vis_payloads = s.num_visible_payloads;
1201 if ( vis_payloads > 0 )
1202 {
1203 str += ", payload";
1204 str += (vis_payloads > 1) ? "s: " : ": ";
1205 for ( const auto& pld : s.payloads )
1206 {
1207 if ( pld.second )
1208 str += to_string(pld.first) + (--vis_payloads ? ", " : "");
1209 }
1210 }
1211 if ( *s.user )
1212 str += ", user: " + string(s.user);
1213 }
1214 }
1215
1216 if ( num_visible_clients > 0 )
1217 {
1218 str += "\nclients size: " + to_string(num_visible_clients);
1219 for ( const auto& c : clients )
1220 {
1221 if ( c.visibility == false )
1222 continue;
1223
1224 str += "\n id: " + to_string(c.id)
1225 + ", service: " + to_string(c.service);
1226 if ( c.version[0] != '\0' )
1227 str += ", version: " + string(c.version);
1228
1229 auto vis_payloads = c.num_visible_payloads;
1230 if ( vis_payloads )
1231 {
1232 str += ", payload";
1233 str += (vis_payloads > 1) ? "s: " : ": ";
1234 for ( const auto& pld : c.payloads )
1235 {
1236 if ( pld.second )
1237 str += to_string(pld.first) + (--vis_payloads ? ", " : "");
1238 }
1239 }
1240 }
1241 }
1242
1243 if ( any_of(network_protos.begin(), network_protos.end(),
1244 [] (const NetProto_t& proto) { return proto.second; }) )
1245 {
1246 str += "\nnetwork proto: ";
1247 auto total = network_protos.size();
1248 while ( total-- )
1249 {
1250 const auto& proto = network_protos[total];
1251 if ( proto.second == true )
1252 str += to_string(proto.first) + (total? ", " : "");
1253 }
1254 }
1255
1256 if ( any_of(xport_protos.begin(), xport_protos.end(),
1257 [] (const XProto_t& proto) { return proto.second; }) )
1258 {
1259 str += "\ntransport proto: ";
1260 auto total = xport_protos.size();
1261 while ( total-- )
1262 {
1263 const auto& proto = xport_protos[total];
1264 if ( proto.second == true )
1265 str += to_string(proto.first) + (total? ", " : "");
1266 }
1267 }
1268
1269 auto total = tcp_fpids.size();
1270 if ( total )
1271 {
1272 str += "\ntcp fingerprint: ";
1273 for ( const auto& fpid : tcp_fpids )
1274 str += to_string(fpid) + (--total ? ", " : "");
1275 }
1276
1277 total = ua_fps.size();
1278 if ( total )
1279 {
1280 str += "\nua fingerprint: ";
1281 for ( const auto& fp : ua_fps )
1282 {
1283 str += to_string(fp.fpid) + " (type: " + to_string(fp.fp_type);
1284 if ( fp.jail_broken )
1285 str += ", jail-broken";
1286 if ( fp.device[0] != '\0' )
1287 str += ", device: " + string(fp.device);
1288 str += string(")") + (--total ? ", " : "");
1289 }
1290 }
1291
1292 total = udp_fpids.size();
1293 if ( total )
1294 {
1295 str += "\nudp fingerprint: ";
1296 for ( const auto& fpid : udp_fpids )
1297 str += to_string(fpid) + (--total ? ", " : "");
1298 }
1299
1300 total = smb_fpids.size();
1301 if ( total )
1302 {
1303 str += "\nsmb fingerprint: ";
1304 for ( const auto& fpid : smb_fpids )
1305 str += to_string(fpid) + (--total ? ", " : "");
1306 }
1307
1308 if ( !netbios_name.empty() )
1309 str += "\nnetbios name: " + netbios_name;
1310 }
1311