/* * * (C) 2015-20 - ntop.org * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "ntop_includes.h" /* #define HOST_POOLS_DEBUG 1 */ /* *************************************** */ HostPools::HostPools(NetworkInterface *_iface) { tree = tree_shadow = NULL; #ifdef NTOPNG_PRO children_safe = forge_global_dns = NULL; routing_policy_id = NULL; if((children_safe = (bool*)calloc(MAX_NUM_HOST_POOLS, sizeof(bool))) == NULL) throw 1; if((forge_global_dns = (bool*)calloc(MAX_NUM_HOST_POOLS, sizeof(bool))) == NULL) throw 1; if((routing_policy_id = (u_int8_t*)calloc(MAX_NUM_HOST_POOLS, sizeof(u_int8_t))) == NULL) throw 1; for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) routing_policy_id[i] = DEFAULT_ROUTING_TABLE_ID; if((volatile_members = (volatile_members_t**)calloc(MAX_NUM_HOST_POOLS, sizeof(volatile_members_t*))) == NULL || (volatile_members_lock = new Mutex*[MAX_NUM_HOST_POOLS]) == NULL || (pool_shaper = (u_int16_t*)calloc(MAX_NUM_HOST_POOLS, sizeof(u_int16_t))) == NULL || (schedule_bitmap = (u_int32_t*)calloc(MAX_NUM_HOST_POOLS, sizeof(u_int32_t))) == NULL || (enforce_quotas_per_pool_member = (bool*)calloc(MAX_NUM_HOST_POOLS, sizeof(bool))) == NULL || (enforce_shapers_per_pool_member = (bool*)calloc(MAX_NUM_HOST_POOLS, sizeof(bool))) == NULL) throw 1; for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) { if((volatile_members_lock[i] = new Mutex()) == NULL) throw 2; } #endif stats = stats_shadow = NULL; if((num_active_hosts_inline = (int32_t*)calloc(sizeof(int32_t), MAX_NUM_HOST_POOLS)) == NULL || (num_active_hosts_offline = (int32_t*)calloc(sizeof(int32_t), MAX_NUM_HOST_POOLS)) == NULL || (num_active_l2_devices_inline = (int32_t*)calloc(sizeof(int32_t), MAX_NUM_HOST_POOLS)) == NULL || (num_active_l2_devices_offline = (int32_t*)calloc(sizeof(int32_t), MAX_NUM_HOST_POOLS)) == NULL) throw 1; latest_swap = 0; if((swap_lock = new Mutex()) == NULL) throw 3; if(_iface) iface = _iface; reloadPools(); loadFromRedis(); max_num_pools = MAX_NUM_HOST_POOLS; ntop->getTrace()->traceEvent(TRACE_INFO, "Host Pools Available: %u", MAX_NUM_HOST_POOLS); } /* *************************************** */ void HostPools::deleteStats(HostPoolStats ***hps) { if(hps) { if(*hps) { for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) if((*hps)[i]) delete (*hps)[i]; delete [] *hps; *hps = NULL; } } } /* *************************************** */ HostPools::~HostPools() { if(num_active_hosts_inline) free(num_active_hosts_inline); if(num_active_hosts_offline) free(num_active_hosts_offline); if(num_active_l2_devices_inline) free(num_active_l2_devices_inline); if(num_active_l2_devices_offline) free(num_active_l2_devices_offline); if(tree_shadow) delete tree_shadow; if(tree) delete tree; if(swap_lock) delete swap_lock; dumpToRedis(); if(stats) deleteStats(&stats); if(stats_shadow) deleteStats(&stats_shadow); #ifdef NTOPNG_PRO if(children_safe) free(children_safe); if(forge_global_dns) free(forge_global_dns); if(routing_policy_id) free(routing_policy_id); if(pool_shaper) free(pool_shaper); if(schedule_bitmap) free(schedule_bitmap); if(enforce_quotas_per_pool_member) free(enforce_quotas_per_pool_member); if(enforce_shapers_per_pool_member) free(enforce_shapers_per_pool_member); if(volatile_members_lock) { for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) { if(volatile_members_lock[i]) delete volatile_members_lock[i]; } delete []volatile_members_lock; } if(volatile_members) { for(int pool_id = 0; pool_id < MAX_NUM_HOST_POOLS; pool_id++) { volatile_members_t *current, *tmp; HASH_ITER(hh, volatile_members[pool_id], current, tmp) { HASH_DEL(volatile_members[pool_id], current); free(current->host_or_mac); free(current); } if(volatile_members[pool_id]) free(volatile_members[pool_id]); } free(volatile_members); } #endif } /* *************************************** */ void HostPools::swap(VlanAddressTree *new_trees, HostPoolStats **new_stats) { swap_lock->lock(__FILE__, __LINE__); while(time(NULL) - latest_swap < 1) { swap_lock->unlock(__FILE__, __LINE__); sleep(1); /* Force at least 1 sec. time between consecutive swaps */ swap_lock->lock(__FILE__, __LINE__); } /* Swap statistics */ if(new_stats) { if(stats) { if(stats_shadow) deleteStats(&stats_shadow); stats_shadow = stats; } stats = new_stats; } /* Swap address trees */ if(new_trees) { if(tree) { if(tree_shadow) delete tree_shadow; tree_shadow = tree; } tree = new_trees; } latest_swap = time(NULL); swap_lock->unlock(__FILE__, __LINE__); } /* *************************************** */ void HostPools::dumpToRedis() { char key[128]; char buf[32]; Redis *redis = ntop->getRedis(); if((!redis) || (! stats) || (! iface)) return; snprintf(key, sizeof(key), HOST_POOL_SERIALIZED_KEY, iface->get_id()); for(int i = 0; ineedsReset()) { snprintf(buf, sizeof(buf), "%d", i); char *value = stats[i]->serialize(iface); if(value) { redis->hashSet(key, buf, value); free(value); } } } #ifdef HAVE_NEDGE // Save the deadline time for quota expiration, assuming quota is reset at midnight snprintf(buf, sizeof(buf), "%u", Utils::roundTime(time(0), 86400, ntop->get_time_offset()) - 86400); redis->hashSet(key, (char *)"deadline", buf); #endif } /* *************************************** */ void HostPools::loadFromRedis() { char key[CONST_MAX_LEN_REDIS_KEY], buf[32], *value; json_object *obj; enum json_tokener_error jerr = json_tokener_success; Redis *redis = ntop->getRedis(); snprintf(key, sizeof(key), HOST_POOL_SERIALIZED_KEY, iface->get_id()); if((!redis) || (!stats) || (!iface)) return; #ifdef HAVE_NEDGE time_t deadline = 0; if(redis->hashGet(key, (char *)"deadline", buf, sizeof(buf)) == 0) { sscanf(buf, "%lu", &deadline); if(time(0) > deadline) return; /* Expired */ } #endif if((value = (char *) malloc(POOL_MAX_SERIALIZED_LEN)) == NULL) { ntop->getTrace()->traceEvent(TRACE_ERROR, "Unable to allocate memory to deserialize %s", key); return; } for(int i = 0; ihashGet(key, buf, value, POOL_MAX_SERIALIZED_LEN) == 0) { if((obj = json_tokener_parse_verbose(value, &jerr)) == NULL) { ntop->getTrace()->traceEvent(TRACE_WARNING, "JSON Parse error [%s] key: %s: %s", json_tokener_error_desc(jerr), key, value); } else { stats[i]->deserialize(iface, obj); json_object_put(obj); } } } } free(value); } /* *************************************** */ void HostPools::luaStats(lua_State *vm) { if(vm) { lua_newtable(vm); for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) luaStats(vm, i); } }; /* *************************************** */ void HostPools::luaStats(lua_State *vm, u_int16_t pool_id) { HostPoolStats *hps; if(vm) { if(stats && pool_id < MAX_NUM_HOST_POOLS) { if((hps = stats[pool_id])) { /* Must use the assigned hps as stats can be swapped and accesses such as stats[pool_id] could yield a NULL value */ hps->lua(vm, iface); lua_push_uint64_table_entry(vm, "num_hosts", getNumPoolHosts(pool_id)); lua_rawseti(vm, -2, pool_id); } } } }; /* *************************************** */ void HostPools::updateStats(struct timeval *tv) { HostPoolStats *hps; if(stats && tv) { for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) if((hps = stats[i])) hps->updateStats(tv); /* Use hps, stats[i] can become NULL after a swap */ } }; /* *************************************** */ void HostPools::incPoolStats(u_int32_t when, u_int16_t host_pool_id, u_int16_t ndpi_proto, ndpi_protocol_category_t category_id, u_int64_t sent_packets, u_int64_t sent_bytes, u_int64_t rcvd_packets, u_int64_t rcvd_bytes) { HostPoolStats *hps = getPoolStats(host_pool_id); if(!hps) return; /* Important to use the assigned hps as a swap can make stats[host_pool_id] NULL */ hps->incStats(when, ndpi_proto, sent_packets, sent_bytes, rcvd_packets, rcvd_bytes); hps->incCategoryStats(when, category_id, sent_bytes, rcvd_bytes); }; /* *************************************** */ #ifdef NTOPNG_PRO void HostPools::reloadVolatileMembers(VlanAddressTree *_trees) { volatile_members_t *current, *tmp; char *at, *member; bool rc; u_int16_t vlan_id; if(!_trees) return; for(int pool_id = 0; pool_id < MAX_NUM_HOST_POOLS; pool_id++) { if(!volatile_members[pool_id]) continue; volatile_members_lock[pool_id]->lock(__FILE__, __LINE__); if(stats && stats[pool_id]) { /* The pool exists */ HASH_ITER(hh, volatile_members[pool_id], current, tmp) { member = strdup(current->host_or_mac); if((at = strchr(member, '@'))) { vlan_id = atoi(at + 1); *at = '\0'; } else vlan_id = 0; if(!(rc = _trees->addAddress(vlan_id, member, pool_id)) #ifdef HOST_POOLS_DEBUG || true #endif ) ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s VOLATILE tree node for %s [vlan %i] [host pool: %i]", rc ? "Successfully added" : "Unable to add", member, vlan_id, pool_id); free(member); } } else { /* The pool no longer exists */ HASH_ITER(hh, volatile_members[pool_id], current, tmp) { HASH_DEL(volatile_members[pool_id], current); free(current->host_or_mac); free(current); } } volatile_members_lock[pool_id]->unlock(__FILE__, __LINE__); } #ifdef HAVE_NEDGE /* Note: we must re-evaluate the active flows as a captive portal host may be blocked now */ if(iface && (iface->getIfType() == interface_type_NETFILTER)) ((NetfilterInterface *) iface)->setPolicyChanged(); #endif }; /* *************************************** */ void HostPools::addVolatileMember(char *host_or_mac, u_int16_t host_pool_id, time_t lifetime) { volatile_members_t *m; if(!host_or_mac || host_pool_id >= MAX_NUM_HOST_POOLS) return; volatile_members_lock[host_pool_id]->lock(__FILE__, __LINE__); HASH_FIND_STR(volatile_members[host_pool_id], host_or_mac, m); if(m == NULL) { m = (volatile_members_t*)calloc(1, sizeof(volatile_members_t)); m->host_or_mac = strdup(host_or_mac); HASH_ADD_STR(volatile_members[host_pool_id], host_or_mac, m); } m->lifetime = time(NULL) + lifetime; #ifdef HOST_POOLS_DEBUG ntop->getTrace()->traceEvent(TRACE_NORMAL, "Adding %s VOLATILE MEMBER to the hash table [host pool: %i] [lifetime: %i]", host_or_mac, host_pool_id, lifetime); #endif volatile_members_lock[host_pool_id]->unlock(__FILE__, __LINE__); } /* *************************************** */ void HostPools::incPoolNumDroppedFlows(u_int16_t pool_id) { HostPoolStats *hps = getPoolStats(pool_id); if(!hps) return; hps->incNumDroppedFlows(); } /* *************************************** */ void HostPools::resetPoolsStats(u_int16_t pool_filter) { HostPoolStats *hps; if(stats) { if(pool_filter != (u_int16_t)-1) { if((hps = getPoolStats(pool_filter))) hps->resetStats(); } else { for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) { if((hps = stats[i])) { /* Must use the assigned hps as stats can be swapped and accesses such as stats[i] could yield a NULL value */ hps->resetStats(); } } } } } /* *************************************** */ void HostPools::checkPoolsStatsReset() { HostPoolStats *hps; if(stats) { for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) { if((hps = stats[i])) { /* Must use the assigned hps as stats can be swapped and accesses such as stats[i] could yield a NULL value */ hps->checkStatsReset(); } } } } /* *************************************** */ void HostPools::luaVolatileMembers(lua_State *vm) { volatile_members_t *current, *tmp; int i; time_t now = time(NULL); if(!vm) return; lua_newtable(vm); for(int pool_id = 0; pool_id < MAX_NUM_HOST_POOLS; pool_id++) { if(!volatile_members[pool_id]) continue; volatile_members_lock[pool_id]->lock(__FILE__, __LINE__); if(stats && stats[pool_id]) { /* The pool exists */ lua_newtable(vm); i = 0; HASH_ITER(hh, volatile_members[pool_id], current, tmp) { lua_newtable(vm); lua_push_str_table_entry(vm, "member", current->host_or_mac); lua_push_float_table_entry(vm, "residual_lifetime", current->lifetime - now); lua_push_bool_table_entry(vm, "expired", current->lifetime - now < 0); lua_rawseti(vm, -2, ++i); } lua_rawseti(vm, -2, pool_id); } volatile_members_lock[pool_id]->unlock(__FILE__, __LINE__); } }; /* *************************************** */ void HostPools::addToPool(char *host_or_mac, u_int16_t user_pool_id, int32_t lifetime_secs) { char key[128], pool_buf[16]; #ifdef HOST_POOLS_DEBUG ntop->getTrace()->traceEvent(TRACE_NORMAL, "Adding %s as %s host pool member [pool id: %i]", host_or_mac, lifetime_secs <= 0 ? "PERMANENT" : "VOLATILE", user_pool_id); #endif if(lifetime_secs > 0) addVolatileMember(host_or_mac, user_pool_id, (u_int32_t)lifetime_secs); else { snprintf(pool_buf, sizeof(pool_buf), "%u", user_pool_id); snprintf(key, sizeof(key), HOST_POOL_MEMBERS_KEY, iface->get_id(), pool_buf); ntop->getRedis()->sadd(key, host_or_mac); /* New member added */ } reloadPools(); } /* *************************************** */ void HostPools::purgeExpiredVolatileMembers() { volatile_members_t *current, *tmp; bool purged = false; time_t now = time(NULL); for(int pool_id = 0; pool_id < MAX_NUM_HOST_POOLS; pool_id++) { volatile_members_lock[pool_id]->lock(__FILE__, __LINE__); HASH_ITER(hh, volatile_members[pool_id], current, tmp) { #ifdef HOST_POOLS_DEBUG ntop->getTrace()->traceEvent(TRACE_NORMAL, "Checking VOLATILE MEMBER %s [pool id: %i] for expiration...", current->host_or_mac, pool_id); #endif if(current->lifetime < now) { purged = true; #ifdef HOST_POOLS_DEBUG ntop->getTrace()->traceEvent(TRACE_NORMAL, "Purging expired VOLATILE MEMBER %s [pool id: %i]", current->host_or_mac, pool_id); #endif HASH_DEL(volatile_members[pool_id], current); free(current->host_or_mac); free(current); } } volatile_members_lock[pool_id]->unlock(__FILE__, __LINE__); } if(purged) reloadPools(); } /* *************************************** */ void HostPools::removeVolatileMemberFromPool(char *host_or_mac, u_int16_t user_pool_id) { volatile_members_t *m; bool purged = false; if(user_pool_id == NO_HOST_POOL_ID || user_pool_id >= MAX_NUM_HOST_POOLS || !host_or_mac) return; volatile_members_lock[user_pool_id]->lock(__FILE__, __LINE__); HASH_FIND_STR(volatile_members[user_pool_id], host_or_mac, m); if(m) { HASH_DEL(volatile_members[user_pool_id], m); free(m->host_or_mac); free(m); purged = true; } volatile_members_lock[user_pool_id]->unlock(__FILE__, __LINE__); if(purged) reloadPools(); } #endif /* *************************************** */ void HostPools::lua(lua_State *vm) { u_int32_t hosts = 0, l2_devices = 0; u_int32_t cur_hosts = 0, cur_l2 = 0; u_int32_t active_pools = 0; char buf[8]; lua_newtable(vm); for(int i = 0; i < MAX_NUM_HOST_POOLS; i++) { if((cur_hosts = getNumPoolHosts(i))) hosts += cur_hosts; if((cur_l2 = getNumPoolL2Devices(i))) l2_devices += cur_l2; if(cur_hosts || cur_l2) { lua_newtable(vm); lua_push_uint64_table_entry(vm, "num_hosts", cur_hosts); lua_push_uint64_table_entry(vm, "num_l2_devices", cur_l2); snprintf(buf, sizeof(buf), "%d", i); lua_pushstring(vm, buf); lua_insert(vm, -2); lua_settable(vm, -3); active_pools++; } } lua_pushstring(vm, "num_members_per_pool"); lua_insert(vm, -2); lua_settable(vm, -3); lua_newtable(vm); lua_push_uint64_table_entry(vm, "num_hosts", hosts); lua_push_uint64_table_entry(vm, "num_l2_devices", l2_devices); lua_push_uint64_table_entry(vm, "num_active_pools", active_pools); lua_pushstring(vm, "num_members"); lua_insert(vm, -2); lua_settable(vm, -3); } /* *************************************** */ void HostPools::reloadPools() { char kname[CONST_MAX_LEN_REDIS_KEY]; char **pools, **pool_members, *at, *member; int num_pools, num_members, actual_num_members; u_int16_t _pool_id, vlan_id; VlanAddressTree *new_tree; HostPoolStats **new_stats; Redis *redis = ntop->getRedis(); if(!iface || (iface->get_id() == -1)) return; new_tree = new VlanAddressTree; new_stats = new HostPoolStats*[MAX_NUM_HOST_POOLS]; for(u_int32_t i = 0; i < MAX_NUM_HOST_POOLS; i++) new_stats[i] = NULL; snprintf(kname, sizeof(kname), HOST_POOL_IDS_KEY, iface->get_id()); /* Always allocate default pool stats */ if(stats && stats[0]) /* Duplicate existing statistics */ new_stats[0] = new HostPoolStats(*stats[0]); else /* Brand new statistics */ new_stats[0] = new HostPoolStats(iface); /* Keys are pool ids */ num_pools = redis->smembers(kname, &pools); for(int i = 0; i < num_pools; i++) { if(!pools[i]) continue; _pool_id = (u_int16_t)atoi(pools[i]); if(_pool_id >= MAX_NUM_HOST_POOLS) { ntop->getTrace()->traceEvent(TRACE_WARNING, "Ignoring pool [pool id: %2d]. " "Maximum number of host pools for this license is %u, inclusive of the Not Assigned pool.", _pool_id, MAX_NUM_HOST_POOLS); free(pools[i]); continue; } if(_pool_id != 0) { /* Pool id 0 stats already updated */ if(stats && stats[_pool_id]) /* Duplicate existing statistics */ new_stats[_pool_id] = new HostPoolStats(*stats[_pool_id]); else /* Brand new statistics */ new_stats[_pool_id] = new HostPoolStats(iface); } snprintf(kname, sizeof(kname), HOST_POOL_DETAILS_KEY, iface->get_id(), _pool_id); #ifdef NTOPNG_PRO char rsp[16] = { 0 }; children_safe[_pool_id] = ((redis->hashGet(kname, (char*)CONST_CHILDREN_SAFE, rsp, sizeof(rsp)) != -1) && (!strcmp(rsp, "true"))); forge_global_dns[_pool_id] = ((redis->hashGet(kname, (char*)CONST_FORGE_GLOBAL_DNS, rsp, sizeof(rsp)) != -1) && (!strcmp(rsp, "true"))); routing_policy_id[_pool_id] = (redis->hashGet(kname, (char*)CONST_ROUTING_POLICY_ID, rsp, sizeof(rsp)) != -1) ? atoi(rsp) : DEFAULT_ROUTING_TABLE_ID; pool_shaper[_pool_id] = (redis->hashGet(kname, (char*)CONST_POOL_SHAPER_ID, rsp, sizeof(rsp)) != -1) ? atoi(rsp) : DEFAULT_SHAPER_ID; schedule_bitmap[_pool_id] = (redis->hashGet(kname, (char*)CONST_SCHEDULE_BITMAP, rsp, sizeof(rsp)) != -1) ? strtol(rsp, NULL, 16) : DEFAULT_TIME_SCHEDULE; enforce_quotas_per_pool_member[_pool_id] = ((redis->hashGet(kname, (char*)CONST_ENFORCE_QUOTAS_PER_POOL_MEMBER, rsp, sizeof(rsp)) != -1) && (!strcmp(rsp, "true")));; enforce_shapers_per_pool_member[_pool_id] = ((redis->hashGet(kname, (char*)CONST_ENFORCE_SHAPERS_PER_POOL_MEMBER, rsp, sizeof(rsp)) != -1) && (!strcmp(rsp, "true")));; #ifdef HOST_POOLS_DEBUG redis->hashGet(kname, (char*)"name", rsp, sizeof(rsp)); ntop->getTrace()->traceEvent(TRACE_NORMAL, "Loading pool [iteration: %u][pool_id: %u][name: %s]" "[children_safe: %i]" "[forge_global_dns: %i]" "[pool_shaper: %i]" "[schedule_bitmap: %i]" "[enforce_quotas_per_pool_member: %i]" "[enforce_shapers_per_pool_member: %i]", i, _pool_id, rsp, children_safe[_pool_id], forge_global_dns[_pool_id], pool_shaper[_pool_id], schedule_bitmap[_pool_id], enforce_quotas_per_pool_member[_pool_id], enforce_shapers_per_pool_member[_pool_id]); #endif #endif /* NTOPNG_PRO */ snprintf(kname, sizeof(kname), HOST_POOL_MEMBERS_KEY, iface->get_id(), pools[i]); /* Pool members are the elements of the list */ if((num_members = redis->smembers(kname, &pool_members)) > 0) { // NOTE: the auto-assigned host_pool must not be limited as it receives devices assigments automatically actual_num_members = min_val((u_int32_t)num_members, ((_pool_id == ntop->getPrefs()->get_auto_assigned_pool_id()) ? MAX_NUM_INTERFACE_HOSTS : MAX_NUM_POOL_MEMBERS)); if(actual_num_members < num_members) { ntop->getTrace()->traceEvent(TRACE_WARNING, "Too many members [pool id: %2d][pool members: %d]. " "Maximum number of pool members for this license is %u, so %u pool members will be ignored.", _pool_id, num_members, actual_num_members, num_members - actual_num_members, actual_num_members); } for(int k = 0; k < actual_num_members; k++) { member = pool_members[k]; if(!member) continue; if((at = strchr(member, '@'))) { vlan_id = atoi(at + 1); *at = '\0'; } else vlan_id = 0; bool rc; if(!(rc = new_tree->addAddress(vlan_id, member, _pool_id)) #ifdef HOST_POOLS_DEBUG || true #endif ) ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s tree node for %s [vlan %i] [host pool: %s]", rc ? "Successfully added" : "Unable to add", member, vlan_id, pools[i]); free(member); } free(pool_members); } free(pools[i]); } if(pools) free(pools); #ifdef NTOPNG_PRO if(ntop->getPrefs()->isCaptivePortalEnabled()) reloadVolatileMembers(new_tree /* Reload only on the new */); #endif swap(new_tree, new_stats); iface->refreshHostPools(); } /* *************************************** */ bool HostPools::findMacPool(const u_int8_t * const mac, u_int16_t *found_pool) { VlanAddressTree *cur_tree; /* must use this as tree can be swapped */ int16_t ret; if(!tree || !(cur_tree = tree)) return(false); ret = cur_tree->findMac(0, mac); if(ret != -1) { *found_pool = (u_int16_t)ret; return(true); } return(false); } /* *************************************** */ bool HostPools::findMacPool(Mac *mac, u_int16_t *found_pool) { if(mac->isSpecialMac()) return(false); return findMacPool(mac->get_mac(), found_pool); } /* *************************************** */ bool HostPools::findIpPool(IpAddress *ip, u_int16_t vlan_id, u_int16_t *found_pool, patricia_node_t **found_node) { VlanAddressTree *cur_tree; /* must use this as tree can be swapped */ #ifdef HOST_POOLS_DEBUG char buf[128]; #endif if(!tree || !(cur_tree = tree)) return(false); *found_node = (patricia_node_t*)ip->findAddress(cur_tree->getAddressTree(vlan_id)); if(*found_node) { #ifdef HOST_POOLS_DEBUG ntop->getTrace()->traceEvent(TRACE_NORMAL, "Found pool for %s [pool id: %i]", ip->print(buf, sizeof(buf)), (*found_node)->user_data); #endif *found_pool = (*found_node)->user_data; return(true); } return(false); } /* *************************************** */ u_int16_t HostPools::getPool(Host *h) { u_int16_t pool_id; patricia_node_t *node; bool found = false; if(h) { if(h->getMac()) found = findMacPool(h->getMac(), &pool_id); if(!found && h->get_ip()) { found = findIpPool(h->get_ip(), h->get_vlan_id(), &pool_id, &node); } } if(!found) return NO_HOST_POOL_ID; return pool_id; } /* *************************************** */ u_int16_t HostPools::getPool(Mac *m) { u_int16_t pool_id; bool found = false; if(m) found = findMacPool(m, &pool_id); if(!found) return NO_HOST_POOL_ID; return pool_id; }