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