/*
* Copyright (C) 1998-2007 Luca Deri <deri@ntop.org>
*
* http://www.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 2 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.h"
/* #define HASH_DEBUG */
/* #define DNS_DEBUG */
#ifdef HASH_DEBUG
static void hashSanityCheck();
static void hostHashSanityCheck(HostTraffic *host);
#endif
/* ******************************* */
u_int hashHost(HostAddr *hostIpAddress, u_char *ether_addr,
short* useIPAddressForSearching, HostTraffic **el,
int actualDeviceId) {
u_int idx = 0;
*el = NULL;
if(myGlobals.runningPref.dontTrustMACaddr) /* MAC addresses don't make sense here */
(*useIPAddressForSearching) = 1;
if((*useIPAddressForSearching) && (hostIpAddress == NULL)) {
#if 0
traceEvent(CONST_TRACE_WARNING, "Index calculation problem (hostIpAddress=%x, ether_addr=%x)",
hostIpAddress, ether_addr);
#endif
return(FLAG_NO_PEER);
}
if(((*useIPAddressForSearching) == 1) || ((ether_addr == NULL) && (hostIpAddress != NULL))) {
if(myGlobals.runningPref.trackOnlyLocalHosts
&& (!isLocalAddress(hostIpAddress, actualDeviceId, NULL, NULL))
&& (!_pseudoLocalAddress(hostIpAddress, NULL, NULL))) {
*el = myGlobals.otherHostEntry;
return(OTHER_HOSTS_ENTRY);
} else {
/* idx = hostIpAddress->s_addr; */
if(hostIpAddress->hostFamily == AF_INET)
idx = (hostIpAddress->Ip4Address.s_addr & 0xffff)
^ ((hostIpAddress->Ip4Address.s_addr >> 15) & 0xffff);
#ifdef INET6
else if(hostIpAddress->hostFamily == AF_INET6)
idx = in6_hash(&hostIpAddress->Ip6Address);
#endif
}
(*useIPAddressForSearching) = 1;
} else if(memcmp(ether_addr, myGlobals.broadcastEntry->ethAddress, LEN_ETHERNET_ADDRESS) == 0) {
*el = myGlobals.broadcastEntry;
return(BROADCAST_HOSTS_ENTRY);
} else if(hostIpAddress == NULL) {
memcpy(&idx, ðer_addr[LEN_ETHERNET_ADDRESS-sizeof(u_int)], sizeof(u_int));
(*useIPAddressForSearching) = 0;
} else if(isBroadcastAddress(hostIpAddress, NULL, NULL)) {
*el = myGlobals.broadcastEntry;
return(BROADCAST_HOSTS_ENTRY);
} else if(isPseudoLocalAddress(hostIpAddress, actualDeviceId, NULL, NULL)) {
memcpy(&idx, ðer_addr[LEN_ETHERNET_ADDRESS-sizeof(u_int)], sizeof(u_int));
(*useIPAddressForSearching) = 0;
} else {
if(hostIpAddress != NULL) {
if(myGlobals.runningPref.trackOnlyLocalHosts
&& (!isPseudoLocalAddress(hostIpAddress, actualDeviceId, NULL, NULL))) {
*el = myGlobals.otherHostEntry;
return(OTHER_HOSTS_ENTRY);
} else {
/* idx = hostIpAddress->s_addr; */
if(hostIpAddress->hostFamily == AF_INET)
idx = (hostIpAddress->Ip4Address.s_addr & 0xffff) ^ ((hostIpAddress->Ip4Address.s_addr >> 15) & 0xffff);
#ifdef INET6
else if(hostIpAddress->hostFamily == AF_INET6)
idx = in6_hash(&hostIpAddress->Ip6Address);
#endif
}
} else {
idx = FLAG_NO_PEER;
traceEvent(CONST_TRACE_WARNING, "Index calculation problem (1)");
}
(*useIPAddressForSearching) = 1;
}
idx = idx % myGlobals.device[actualDeviceId].actualHashSize;
/* Skip reserved entries */
if((idx == BROADCAST_HOSTS_ENTRY) || (idx == OTHER_HOSTS_ENTRY))
idx = FIRST_HOSTS_ENTRY;
return(idx);
}
/* ************************************ */
u_int hashFcHost(FcAddress *fcaddr, u_short vsanId, HostTraffic **el,
int actualDeviceId)
{
u_int idx = 0;
*el = NULL;
if(fcaddr == NULL) {
#if 0
traceEvent(CONST_TRACE_WARNING, "Index calculation problem (hostIpAddress=%x, ether_addr=%x)",
hostIpAddress, ether_addr);
#endif
return(FLAG_NO_PEER);
}
idx = (fcaddr->domain & 0xff) ^ (fcaddr->area & 0xff) ^ (fcaddr->port & 0xff) ^ vsanId;
if(actualDeviceId == -1) {
idx = idx % CONST_HASH_INITIAL_SIZE;
} else {
idx = idx % myGlobals.device[actualDeviceId].actualHashSize;
}
/* Skip reserved entries */
if((idx == BROADCAST_HOSTS_ENTRY) || (idx == OTHER_HOSTS_ENTRY))
idx = FIRST_HOSTS_ENTRY;
return(idx);
}
/* ************************************ */
/*
Description:
This function is called when a host is freed. Therefore
it is necessary to free all the (eventual) sessions of
such host.
*/
static void freeHostSessions(HostTraffic *host, int theDevice) {
int i;
if(host->l2Family == FLAG_HOST_TRAFFIC_AF_ETH) {
for(i=0; i<MAX_TOT_NUM_SESSIONS; i++) {
IPSession *prevSession, *nextSession, *theSession;
if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN /* i.e. active, not cleanup */ )
return;
if(host->numHostSessions == 0) return;
accessMutex(&myGlobals.tcpSessionsMutex, "freeHostSessions");
prevSession = theSession = myGlobals.device[theDevice].tcpSession[i];
while(theSession != NULL) {
nextSession = theSession->next;
if(host->numHostSessions == 0) break;
if((theSession->initiator == host) || (theSession->remotePeer == host)) {
if(myGlobals.device[theDevice].tcpSession[i] == theSession) {
myGlobals.device[theDevice].tcpSession[i] = nextSession;
prevSession = myGlobals.device[theDevice].tcpSession[i];
} else
prevSession->next = nextSession;
freeSession(theSession, theDevice, 0 /* don't allocate */,
0 /* locked by the purge thread */);
theSession = prevSession;
} else {
prevSession = theSession;
theSession = nextSession;
}
if(theSession && (theSession->next == theSession)) {
traceEvent(CONST_TRACE_WARNING, "Internal Error (1)");
}
} /* while */
releaseMutex(&myGlobals.tcpSessionsMutex);
ntop_conditional_sched_yield(); /* Allow other threads to run */
} /* for */
#ifndef DELAY_SESSION_PURGE
if(host->numHostSessions > 0) {
traceEvent(CONST_TRACE_ERROR, "====> Host %s/%s has %d sessions still to be purged",
host->hostNumIpAddress, host->hostResolvedName, host->numHostSessions);
}
#endif
}
else {
for(i=0; i<MAX_TOT_NUM_SESSIONS; i++) {
FCSession *prevSession, *nextSession, *theSession;
if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN /* i.e. active, not cleanup */ )
return;
if(host->numHostSessions == 0) return;
accessMutex(&myGlobals.fcSessionsMutex, "freeHostSessions");
prevSession = theSession = myGlobals.device[theDevice].fcSession[i];
while(theSession != NULL) {
nextSession = theSession->next;
if(host->numHostSessions == 0) break;
if((theSession->initiator == host) || (theSession->remotePeer == host)) {
if(myGlobals.device[theDevice].fcSession[i] == theSession) {
myGlobals.device[theDevice].fcSession[i] = nextSession;
prevSession = myGlobals.device[theDevice].fcSession[i];
} else
prevSession->next = nextSession;
freeFcSession(theSession, theDevice, 0 /* don't allocate */,
0 /* locked by the purge thread */);
theSession = prevSession;
} else {
prevSession = theSession;
theSession = nextSession;
}
if(theSession && (theSession->next == theSession)) {
traceEvent(CONST_TRACE_WARNING, "Internal Error (1)");
}
} /* while */
releaseMutex(&myGlobals.fcSessionsMutex);
ntop_conditional_sched_yield(); /* Allow other threads to run */
} /* for */
#ifndef DELAY_SESSION_PURGE
if(host->numHostSessions > 0) {
traceEvent(CONST_TRACE_ERROR, "====> Host %s/%s has %d sessions still to be purged",
host->hostNumIpAddress, host->hostResolvedName, host->numHostSessions);
}
#endif
}
}
/* **************************************** */
void freeHostInfo(HostTraffic *host, int actualDeviceId) {
u_int i, deleteAddressFromCache = 1;
if(host == NULL) {
traceEvent(CONST_TRACE_WARNING, "Attempting to call freeHostInfo(NULL)");
return;
}
/* If this is one of the special ones, let's clear the other pointer to it
* to prevent a free of freed memory error later.
*/
if(host == myGlobals.otherHostEntry) {
traceEvent(CONST_TRACE_WARNING, "Attempting to call freeHostInfo(otherHostEntry)");
return;
}
if(host == myGlobals.broadcastEntry) {
traceEvent(CONST_TRACE_WARNING, "Attempting to call freeHostInfo(broadcastEntry)");
return;
}
if((host->magic != CONST_MAGIC_NUMBER) && (host->magic != CONST_UNMAGIC_NUMBER)) {
traceEvent(CONST_TRACE_ERROR, "Bad magic number (expected=%d/real=%d) freeHostInfo()",
CONST_MAGIC_NUMBER, host->magic);
return;
}
/* Flag that this entry is being deleted. */
host->magic = CONST_UNMAGIC_NUMBER;
#ifdef DEBUG
traceEvent(CONST_TRACE_INFO, "Entering freeHostInfo(%u)", host->hostTrafficBucket);
#endif
/* ********** */
#if 0
traceEvent(CONST_TRACE_INFO, "HOST_FREE_DEBUG: Deleting a hash_hostTraffic entry [%s/%s/%s][idx=%d]",
host->ethAddressString, host->hostNumIpAddress, host->hostResolvedName, host->hostTrafficBucket);
#endif
if(deleteAddressFromCache) {
datum key_data;
if(host->hostIpAddress.hostFamily == AF_INET) {
key_data.dptr = (void*)&host->hostIpAddress.Ip4Address.s_addr;
key_data.dsize = 4;
}
#ifdef INET6
else if(host->hostIpAddress.hostFamily == AF_INET6) {
key_data.dptr = (void*)&host->hostIpAddress.Ip6Address.s6_addr;
key_data.dsize = 16;
}
#endif
else
key_data.dsize = 0;
if(key_data.dsize && (key_data.dptr != NULL)) {
gdbm_delete(myGlobals.addressQueueFile, key_data);
#ifdef DNS_DEBUG
traceEvent(CONST_TRACE_INFO, "HOST_FREE_DEBUG: Deleting from GDBM address cache host [%s/%s]",
host->hostNumIpAddress, host->hostResolvedName);
#endif
}
}
handlePluginHostCreationDeletion(host, (u_short)actualDeviceId, 0 /* host deletion */);
/* Make sure this host is not part of the ipTrafficMatrixHosts list */
if((myGlobals.device[actualDeviceId].ipTrafficMatrix != NULL)
&& (myGlobals.device[actualDeviceId].numHosts > 0)
&& isMatrixHost(host, actualDeviceId)) {
int id = matrixHostHash(host, actualDeviceId, 0);
myGlobals.device[actualDeviceId].ipTrafficMatrixHosts[id] = NULL;
for(i=0; i<myGlobals.device[actualDeviceId].numHosts-1; i++) {
myGlobals.device[actualDeviceId].ipTrafficMatrix[id*myGlobals.device[actualDeviceId].numHosts+i] = NULL;
myGlobals.device[actualDeviceId].ipTrafficMatrix[i*myGlobals.device[actualDeviceId].numHosts+id] = NULL;
}
}
if(myGlobals.device[actualDeviceId].fcTrafficMatrix != NULL) {
int id = matrixHostHash (host, actualDeviceId, 0);
myGlobals.device[actualDeviceId].fcTrafficMatrixHosts[id] = NULL;
for(i=0; i<myGlobals.device[actualDeviceId].numHosts-1; i++) {
myGlobals.device[actualDeviceId].fcTrafficMatrix[id*myGlobals.device[actualDeviceId].numHosts+i] = NULL;
myGlobals.device[actualDeviceId].fcTrafficMatrix[i*myGlobals.device[actualDeviceId].numHosts+id] = NULL;
}
}
freeHostSessions(host, actualDeviceId);
if(host->fcCounters != NULL) {
if(host->l2Family == FLAG_HOST_TRAFFIC_AF_FC) {
for (i = 0; i < MAX_LUNS_SUPPORTED; i++) {
if(host->fcCounters->activeLuns[i] != NULL) {
free(host->fcCounters->activeLuns[i]);
}
}
}
free(host->fcCounters);
}
myGlobals.device[actualDeviceId].hostsno--;
if(host->protoIPTrafficInfos != NULL) {
for(i=0; i<myGlobals.numIpProtosToMonitor; i++)
if(host->protoIPTrafficInfos[i] != NULL)
free(host->protoIPTrafficInfos[i]);
free(host->protoIPTrafficInfos);
}
if(host->ipProtosList != NULL) {
for(i=0; i<myGlobals.numIpProtosList; i++)
if(host->ipProtosList[i] != NULL)
free(host->ipProtosList[i]);
free(host->ipProtosList);
}
if(host->nonIPTraffic) {
if(host->nonIPTraffic->nbHostName != NULL) free(host->nonIPTraffic->nbHostName);
if(host->nonIPTraffic->nbAccountName != NULL) free(host->nonIPTraffic->nbAccountName);
if(host->nonIPTraffic->nbDomainName != NULL) free(host->nonIPTraffic->nbDomainName);
if(host->nonIPTraffic->nbDescr != NULL) free(host->nonIPTraffic->nbDescr);
if(host->nonIPTraffic->atNodeName != NULL) free(host->nonIPTraffic->atNodeName);
for(i=0; i<MAX_NODE_TYPES; i++)
if(host->nonIPTraffic->atNodeType[i] != NULL) free(host->nonIPTraffic->atNodeType[i]);
if(host->nonIPTraffic->atNodeName != NULL) free(host->nonIPTraffic->atNodeName);
if(host->nonIPTraffic->ipxHostName != NULL) free(host->nonIPTraffic->ipxHostName);
if(host->nonIPTraffic->unknownProtoSent != NULL) free(host->nonIPTraffic->unknownProtoSent);
if(host->nonIPTraffic->unknownProtoRcvd != NULL) free(host->nonIPTraffic->unknownProtoRcvd);
free(host->nonIPTraffic);
}
if(host->nonIpProtoTrafficInfos != NULL) {
NonIpProtoTrafficInfo *list = host->nonIpProtoTrafficInfos;
while(list != NULL) {
NonIpProtoTrafficInfo *next = list->next;
free(list);
list = next;
}
}
if(host->secHostPkts != NULL) {
free(host->secHostPkts);
host->secHostPkts = NULL; /* just to be safe in case of persistent storage */
}
if(host->fingerprint != NULL)
free(host->fingerprint);
if(host->routedTraffic != NULL) free(host->routedTraffic);
if(host->portsUsage != NULL) freePortsUsage(host);
if(myGlobals.runningPref.enablePacketDecoding && (host->protocolInfo != NULL)) {
if(host->protocolInfo->httpVirtualHosts != NULL) {
VirtualHostList *list = host->protocolInfo->httpVirtualHosts;
while(list != NULL) {
VirtualHostList *next = list->next;
if(list->virtualHostName != NULL) /* This is a silly check as it should be true all the time */
free(list->virtualHostName);
free(list);
list = next;
}
}
if(host->protocolInfo->userList != NULL) {
UserList *list = host->protocolInfo->userList;
while(list != NULL) {
UserList *next = list->next;
if(list->userName != NULL)
free(list->userName);
free(list);
list = next;
}
}
if(host->protocolInfo->fileList != NULL) {
FileList *list = host->protocolInfo->fileList;
while(list != NULL) {
FileList *next = list->next;
if(list->fileName != NULL)
free(list->fileName);
free(list);
list = next;
}
}
if(host->protocolInfo->dnsStats != NULL) free(host->protocolInfo->dnsStats);
if(host->protocolInfo->httpStats != NULL) free(host->protocolInfo->httpStats);
if(host->protocolInfo->dhcpStats != NULL) free(host->protocolInfo->dhcpStats);
}
if(host->protocolInfo != NULL) free(host->protocolInfo);
/* ************************************* */
if(host->icmpInfo != NULL) free(host->icmpInfo);
if(host->trafficDistribution != NULL) free(host->trafficDistribution);
if(host->dnsDomainValue != NULL) free(host->dnsDomainValue);
host->dnsDomainValue = NULL;
if(host->dnsTLDValue != NULL) free(host->dnsTLDValue);
host->dnsTLDValue = NULL;
if(host->description != NULL) free(host->description);
if(host->hwModel != NULL) free(host->hwModel);
if(host->community != NULL) free(host->community);
if(host->ip2ccValue != NULL) free(host->ip2ccValue);
host->ip2ccValue = NULL;
/* ********** */
/*
#ifdef HASH_DEBUG
hostHashSanityCheck(host);
#endif
*/
memset(host, 0, sizeof(HostTraffic)); /* Debug code */
free(host);
myGlobals.numPurgedHosts++;
#ifdef DEBUG
traceEvent(CONST_TRACE_INFO, "Leaving freeHostInfo()");
#endif
}
/* ************************************ */
/*
This function is called before the final
cleanup when ntop shutsdown
*/
void freeHostInstances(int actualDeviceId) {
u_int idx, i, max, num=0;
if(myGlobals.runningPref.mergeInterfaces)
max = 1;
else
max = myGlobals.numDevices;
traceEvent(CONST_TRACE_INFO, "FREE_HOST: Start, %d device(s)", max);
for(i=0; i<max; i++) {
if(myGlobals.device[i].dummyDevice) {
i++;
if(i >= myGlobals.numDevices) break;
}
actualDeviceId = i;
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
for(idx=FIRST_HOSTS_ENTRY; idx<myGlobals.device[actualDeviceId].actualHashSize; idx++) {
HostTraffic *el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
if(myGlobals.ntopRunState >= FLAG_NTOPSTATE_SHUTDOWN) break;
while(el != NULL) {
HostTraffic *nextEl = el->next;
el->next = NULL;
num++;
freeHostInfo(el, actualDeviceId);
ntop_conditional_sched_yield(); /* Allow other threads to run */
el = nextEl;
}
myGlobals.device[actualDeviceId].hash_hostTraffic[idx] = NULL;
} /* for */
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
}
traceEvent(CONST_TRACE_INFO, "FREE_HOST: End, freed %d", num);
}
/* ************************************ */
int is_host_ready_to_purge(int actDevice, HostTraffic *el, time_t now) {
/* Time used to decide whether a host need to be purged */
time_t noSessionPurgeTime = now-PARM_HOST_PURGE_MINIMUM_IDLE_NOACTVSES;
time_t withSessionPurgeTime = now-PARM_HOST_PURGE_MINIMUM_IDLE_ACTVSES;
if(el->to_be_deleted
|| (
(el->refCount == 0)
&& ((!myGlobals.runningPref.rFileName)
&& (((el->numHostSessions == 0) && (el->lastSeen < noSessionPurgeTime))
|| ((el->numHostSessions > 0) && (el->lastSeen < withSessionPurgeTime))))
&& (!broadcastHost(el)) && (el != myGlobals.otherHostEntry)
&& (myGlobals.device[actDevice].virtualDevice /* e.g. sFlow/NetFlow */
|| (!myGlobals.runningPref.stickyHosts)
|| ((el->l2Family == FLAG_HOST_TRAFFIC_AF_ETH) &&
((el->hostNumIpAddress[0] == '\0') /* Purge MAC addresses too */
|| (!subnetPseudoLocalHost(el)))) /* Purge remote hosts only */
|| ((el->l2Family == FLAG_HOST_TRAFFIC_AF_FC) &&
(el->fcCounters->hostNumFcAddress[0] == '\0')))))
return(1);
else
return(0);
}
/* ************************************ */
int purgeIdleHosts(int actDevice) {
u_int idx, numFreedBuckets=0, numHosts = 0;
time_t now = time(NULL);
static time_t lastPurgeTime[MAX_NUM_DEVICES];
static char firstRun = 1;
HostTraffic **theFlaggedHosts = NULL;
u_int maxHosts, scannedHosts=0;
float hiresDeltaTime;
struct timeval hiresTimeStart, hiresTimeEnd;
HostTraffic *el, *prev, *next;
/* if(myGlobals.runningPref.rFileName != NULL) return; */
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: purgeIdleHosts() invoked");
#endif
if(firstRun) {
firstRun = 0;
memset(lastPurgeTime, 0, sizeof(lastPurgeTime));
}
gettimeofday(&hiresTimeStart, NULL);
if(now < (lastPurgeTime[actDevice]+PARM_HOST_PURGE_INTERVAL))
return(0); /* Too short */
else
lastPurgeTime[actDevice] = now;
maxHosts = myGlobals.device[actDevice].hostsno; /* save it as it can change */
myGlobals.piMem = maxHosts*sizeof(HostTraffic*);
theFlaggedHosts = (HostTraffic**)calloc(1, myGlobals.piMem);
purgeOldFragmentEntries(actDevice); /* let's do this too */
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: accessMutex(purgeMutex)...calling");
#endif
accessMutex(&myGlobals.purgeMutex, "purgeIdleHosts");
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: accessMutex(purgeMutex)...locked");
#endif
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
accessMutex(&myGlobals.hostsHashLockMutex, "scanIdleLoop");
for(idx=0; idx<myGlobals.device[actDevice].actualHashSize; idx++) {
if(myGlobals.ntopRunState >= FLAG_NTOPSTATE_SHUTDOWN) break;
if((el = myGlobals.device[actDevice].hash_hostTraffic[idx]) != NULL) {
prev = NULL;
while(el) {
if(is_host_ready_to_purge(actDevice, el, now)) {
if(!el->to_be_deleted) {
el->to_be_deleted = 1; /* Delete it at the next run */
/* Skip it and move to next host */
prev = el;
el = el->next;
} else {
/* Host selected for deletion */
theFlaggedHosts[numHosts++] = el;
el->magic = CONST_UNMAGIC_NUMBER;
purgeQueuedV4HostAddress(el->hostIpAddress.Ip4Address.s_addr);
remove_valid_ptr(el);
next = el->next;
if(prev != NULL)
prev->next = next;
else
myGlobals.device[actDevice].hash_hostTraffic[idx] = next;
el->next = NULL;
el = next;
}
} else {
/* Move to next host */
prev = el;
el = el->next;
}
scannedHosts++;
#ifdef MAX_HOSTS_PURGE_PER_CYCLE
if(numHosts >= MAX_HOSTS_PURGE_PER_CYCLE) break;
#endif
if(numHosts >= (maxHosts-1)) break;
} /* while */
if(numHosts >= (maxHosts-1)) {
break;
}
}
}
releaseMutex(&myGlobals.hostsHashLockMutex);
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: releaseMutex(purgeMutex)...calling");
#endif
releaseMutex(&myGlobals.purgeMutex);
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: releaseMutex(purgeMutex)...released");
#endif
traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: Device %d [%s] FINISHED selection, "
"%d [out of %d] hosts selected",
actDevice, myGlobals.device[actDevice].name, numHosts, scannedHosts);
/* Now free the entries */
for(idx=0; idx<numHosts; idx++) {
#ifdef IDLE_PURGE_DEBUG
traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: Purging host %d [last seen=%d]... %s",
idx, theFlaggedHosts[idx]->lastSeen, theFlaggedHosts[idx]->hostResolvedName);
#endif
freeHostInfo(theFlaggedHosts[idx], actDevice);
numFreedBuckets++;
ntop_conditional_sched_yield(); /* Allow other threads to run */
}
free(theFlaggedHosts);
if(myGlobals.runningPref.enableSessionHandling)
scanTimedoutTCPSessions(actDevice); /* let's check timedout sessions too */
gettimeofday(&hiresTimeEnd, NULL);
hiresDeltaTime = timeval_subtract(hiresTimeEnd, hiresTimeStart);
if(numFreedBuckets > 0)
traceEvent(CONST_TRACE_NOISY,
"IDLE_PURGE: Device %d [%s]: %d/%d hosts deleted, elapsed time is %.6f seconds (%.6f per host)",
actDevice, myGlobals.device[actDevice].name,
numFreedBuckets, maxHosts,
hiresDeltaTime,
hiresDeltaTime / numFreedBuckets);
else
traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: Device %s: no hosts [out of %d] deleted",
myGlobals.device[actDevice].name, maxHosts);
return(numFreedBuckets);
}
/* **************************************************** */
void setHostSerial(HostTraffic *el) {
/* Nothing to do */
if(el->hostSerial.serialType != SERIAL_NONE)
return;
if(isFcHost(el)) {
if(el->fcCounters->hostNumFcAddress[0] != '\0') {
el->hostSerial.serialType = SERIAL_FC;
el->hostSerial.value.fcSerial.fcAddress.domain = el->fcCounters->hostFcAddress.domain;
el->hostSerial.value.fcSerial.fcAddress.area = el->fcCounters->hostFcAddress.area;
el->hostSerial.value.fcSerial.fcAddress.port = el->fcCounters->hostFcAddress.port;
el->hostSerial.value.fcSerial.vsanId = el->fcCounters->vsanId;
}
else
traceEvent (CONST_TRACE_ERROR, "setHostSerial: Received NULL FC Address entry");
}
else if(el->hostNumIpAddress[0] == '\0') {
el->hostSerial.serialType = SERIAL_MAC;
memcpy(&el->hostSerial.value.ethSerial.ethAddress, el->ethAddress, LEN_ETHERNET_ADDRESS);
el->hostSerial.value.ethSerial.vlanId = el->vlanId;
} else {
if(el->hostIpAddress.hostFamily == AF_INET){
el->hostSerial.serialType = SERIAL_IPV4;
} else if(el->hostIpAddress.hostFamily == AF_INET6){
el->hostSerial.serialType = SERIAL_IPV6;
}
addrcpy(&el->hostSerial.value.ipSerial.ipAddress, &el->hostIpAddress);
el->hostSerial.value.ipSerial.vlanId = el->vlanId;
}
}
/* ********************************************************* */
/*
Searches a host and returns it. If the host is not
present in the hash a new bucket is created
*/
HostTraffic* _lookupHost(HostAddr *hostIpAddress, u_char *ether_addr, u_int16_t vlanId,
u_char checkForMultihoming, u_char forceUsingIPaddress,
int actualDeviceId, char *file, int line) {
u_int idx, isMultihomed = 0;
HostTraffic *el=NULL;
char buf[MAX_LEN_SYM_HOST_NAME_HTML];
short useIPAddressForSearching = forceUsingIPaddress;
char* symEthName = NULL, *ethAddr;
u_char setSpoofingFlag = 0, locked_mutex = 0;
u_short numRuns=0;
u_int hostFound = 0;
u_int updateIPinfo = 0;
u_int32_t the_local_network, the_local_network_mask;
if((hostIpAddress == NULL) && (ether_addr == NULL)) {
traceEvent(CONST_TRACE_WARNING, "Both Ethernet and IP addresses are NULL in lookupHost()[%s:%d]", file, line);
return(NULL);
}
#ifdef DEBUG
traceEvent(CONST_TRACE_NOISY, "DEBUG: lookupHost(%s, %s, m=%u, f=%u, dev=%d, vlan=%d)",
addrtostr(hostIpAddress),
etheraddr_string(ether_addr, buf),
checkForMultihoming, forceUsingIPaddress, actualDeviceId, vlanId);
#endif
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
idx = hashHost(hostIpAddress, ether_addr,
&useIPAddressForSearching,
&el, actualDeviceId);
/* Remember the side effect of above routine - if -o | --no-mac is set,\
* useIPAddressForSearching is now 1
*/
/* If we found it or had an error */
if(el != NULL)
return(el); /* Found */
else if(idx == FLAG_NO_PEER)
return(NULL);
else {
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
if(el) {
lockHostsHashMutex(el, "_lookupHost");
accessMutex(&myGlobals.hostsHashLockMutex, "lookupHost");
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
locked_mutex = 1;
}
}
while (el != NULL) {
if(el->magic != CONST_MAGIC_NUMBER) {
traceEvent(CONST_TRACE_ERROR,
"Bad magic number (expected=%d/real=%d) [deviceId=%d] lookupHost()[%s:%d]",
CONST_MAGIC_NUMBER, el->magic, actualDeviceId,
file, line);
break; /* Can't trust this chain ... */
}
if(el->hostTrafficBucket != idx) {
traceEvent(CONST_TRACE_WARNING,
"Error: wrong bucketIdx %s/%s (expected=%d/real=%d) [deviceId=%d] lookupHost()[%s:%d]",
el->ethAddressString, el->hostNumIpAddress,
idx, el->hostTrafficBucket, actualDeviceId,
file, line);
}
if(!is_host_ready_to_purge(actualDeviceId, el, myGlobals.actTime)) {
if(useIPAddressForSearching == 0) {
/* compare with the ethernet-address then the IP address */
if(memcmp(el->ethAddress, ether_addr, LEN_ETHERNET_ADDRESS) == 0) {
if((hostIpAddress != NULL) &&
(hostIpAddress->hostFamily == el->hostIpAddress.hostFamily)) {
if((!isMultihomed) && checkForMultihoming) {
/* This is a local address hence this is a potential multihomed host. */
if(!(addrnull(&el->hostIpAddress)) &&
(addrcmp(&el->hostIpAddress,hostIpAddress) != 0)) {
isMultihomed = 1;
FD_SET(FLAG_HOST_TYPE_MULTIHOMED, &el->flags);
} else {
updateIPinfo = 1;
}
}
hostFound = 1;
break;
} else if(hostIpAddress == NULL){ /* Only Mac Addresses */
hostFound = 1;
break;
} else { /* MAC match found and we have the IP - need to update... */
updateIPinfo = 1;
hostFound = 1;
break;
}
} else if((hostIpAddress != NULL) &&
(addrcmp(&el->hostIpAddress, hostIpAddress) == 0)) {
/* Spoofing or duplicated MAC address:
two hosts with the same IP address and different MAC
addresses
*/
if(!hasDuplicatedMac(el)) {
FD_SET(FLAG_HOST_DUPLICATED_MAC, &el->flags);
if(myGlobals.runningPref.enableSuspiciousPacketDump) {
char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY];
traceEvent(CONST_TRACE_WARNING,
"Two MAC addresses found for the same IP address "
"%s: [%s/%s] (spoofing detected?)",
el->hostNumIpAddress,
etheraddr_string(ether_addr, etherbuf), el->ethAddressString);
dumpSuspiciousPacket(actualDeviceId);
}
}
setSpoofingFlag = 1;
hostFound = 1;
break;
}
} else {
/* -o | --no-mac (or NetFlow, which doesn't have MACs) - compare with only the IP address */
if(addrcmp(&el->hostIpAddress, hostIpAddress) == 0) {
hostFound = 1;
break;
}
}
}
el = el->next;
numRuns++;
} /* while */
if(locked_mutex) releaseMutex(&myGlobals.hostsHashLockMutex);
if((hostFound == 1) && (vlanId != NO_VLAN) && (vlanId != el->vlanId) && (!isMultivlaned(el))) {
FD_SET(FLAG_HOST_TYPE_MULTIVLANED, &el->flags);
if(myGlobals.multipleVLANedHostCount == 0) {
traceEvent(CONST_TRACE_ERROR, "mVLAN: Host (identical IP/MAC) found on multiple VLANs");
traceEvent(CONST_TRACE_INFO, "mVLAN: ntop continues but will consolidate and thus probably overcount this traffic");
traceEvent(CONST_TRACE_NOISY, "mVLAN: Up to %d examples will be printed", MAX_MULTIPLE_VLAN_WARNINGS);
}
if(++myGlobals.multipleVLANedHostCount < MAX_MULTIPLE_VLAN_WARNINGS)
traceEvent(CONST_TRACE_NOISY, "mVLAN: Device %d Host %s (%02x:%02x:%02x:%02x:%02x:%02x) VLANs %d and %d",
actualDeviceId,
addrtostr(hostIpAddress),
ether_addr[0],
ether_addr[1],
ether_addr[2],
ether_addr[3],
ether_addr[4],
ether_addr[5],
min(vlanId, el->vlanId),
max(vlanId, el->vlanId));
}
if(numRuns > myGlobals.device[actualDeviceId].hashListMaxLookups)
myGlobals.device[actualDeviceId].hashListMaxLookups = numRuns ;
if(hostFound) {
/* Existing host entry */
if((updateIPinfo == 1) &&
(el->hostNumIpAddress[0] == '\0')) {
/* This entry didn't have IP fields set: let's set them now */
addrcpy(&el->hostIpAddress, hostIpAddress);
strncpy(el->hostNumIpAddress,
_addrtostr(hostIpAddress, buf, sizeof(buf)),
sizeof(el->hostNumIpAddress));
setResolvedName(el, el->hostNumIpAddress, FLAG_HOST_SYM_ADDR_TYPE_IP);
if(myGlobals.runningPref.numericFlag == 0)
ipaddr2str(el->hostIpAddress, 1);
if(isBroadcastAddress(&el->hostIpAddress, NULL, NULL))
FD_SET(FLAG_BROADCAST_HOST, &el->flags);
}
} else {
/* New host entry */
int len;
if(myGlobals.device[actualDeviceId].hostsno >= myGlobals.runningPref.maxNumHashEntries) {
static char messageShown = 0;
if(!messageShown) {
messageShown = 1;
traceEvent(CONST_TRACE_INFO, "WARNING: Max num hash entries (%u) reached (see -x)",
myGlobals.runningPref.maxNumHashEntries);
}
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
if((el = (HostTraffic*)malloc(sizeof(HostTraffic))) == NULL) {
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
memset(el, 0, sizeof(HostTraffic));
el->firstSeen = myGlobals.actTime;
resetHostsVariables(el);
el->vlanId = vlanId;
if(isMultihomed)
FD_SET(FLAG_HOST_TYPE_MULTIHOMED, &el->flags);
if(el->portsUsage != NULL)
freePortsUsage(el);
len = (size_t)myGlobals.numIpProtosList*sizeof(ShortProtoTrafficInfo**);
if((el->ipProtosList = (ShortProtoTrafficInfo**)malloc(len)) == NULL) {
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
memset(el->ipProtosList, 0, len);
len = (size_t)myGlobals.numIpProtosToMonitor*sizeof(ProtoTrafficInfo**);
if((el->protoIPTrafficInfos = (ProtoTrafficInfo**)malloc(len)) == NULL) {
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
memset(el->protoIPTrafficInfos, 0, len);
el->magic = CONST_MAGIC_NUMBER;
el->hostTrafficBucket = idx; /* Set the bucket index */
el->originalHostTrafficBucket = idx; /* Set the bucket index */
/* traceEvent(CONST_TRACE_INFO, "new entry added at bucket %d", idx); */
/* Put the new entry on top of the list */
el->next = myGlobals.device[actualDeviceId].hash_hostTraffic[el->hostTrafficBucket];
myGlobals.device[actualDeviceId].hash_hostTraffic[el->hostTrafficBucket] = el; /* Insert a new entry */
myGlobals.device[actualDeviceId].hostsno++;
if(0)
traceEvent(CONST_TRACE_INFO, "-> Allocated(%d) [tot=%d]",
actualDeviceId, myGlobals.device[actualDeviceId].hostsno);
the_local_network = 0, the_local_network_mask = 0;
if(ether_addr != NULL) {
if((hostIpAddress == NULL)
|| ((hostIpAddress != NULL)
&& isPseudoLocalAddress(hostIpAddress, actualDeviceId, &the_local_network, &the_local_network_mask)
/* && (!isBroadcastAddress(hostIpAddress, &the_local_network, &the_local_network_mask))*/
)) {
char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY];
/* This is a local address and then the
ethernet address does make sense */
ethAddr = etheraddr_string(ether_addr, etherbuf);
memcpy(el->ethAddress, ether_addr, LEN_ETHERNET_ADDRESS);
strncpy(el->ethAddressString, ethAddr, sizeof(el->ethAddressString));
symEthName = getSpecialMacInfo(el, (short)(!myGlobals.separator[0]));
FD_SET(FLAG_SUBNET_LOCALHOST, &el->flags);
FD_SET(FLAG_SUBNET_PSEUDO_LOCALHOST, &el->flags);
/* traceEvent(CONST_TRACE_WARNING, "-> %u/%u", the_local_network, the_local_network_mask); */
} else if(hostIpAddress != NULL) {
/* This is packet that's being routed or belonging to a
remote network that uses the same physical wire (or forged)*/
memcpy(el->lastEthAddress, ether_addr, LEN_ETHERNET_ADDRESS);
if(hostIpAddress != NULL) {
if(hostIpAddress->hostFamily == AF_INET)
memcpy(el->ethAddress, &hostIpAddress->Ip4Address.s_addr, 4); /* Dummy/unique eth address */
#ifdef INET6
else if(hostIpAddress->hostFamily == AF_INET6)
memcpy(el->ethAddress, &hostIpAddress->Ip6Address.s6_addr[8], 4);
#endif
FD_CLR(FLAG_SUBNET_LOCALHOST, &el->flags);
if(isPrivateAddress(hostIpAddress, &the_local_network, &the_local_network_mask)) FD_SET(FLAG_PRIVATE_IP_ADDRESS, &el->flags);
if(!isBroadcastAddress(hostIpAddress, &the_local_network, &the_local_network_mask)) {
if(isPseudoLocalAddress(hostIpAddress, actualDeviceId, &the_local_network, &the_local_network_mask))
FD_SET(FLAG_SUBNET_PSEUDO_LOCALHOST, &el->flags);
else
FD_CLR(FLAG_SUBNET_PSEUDO_LOCALHOST, &el->flags);
}
}
} else {
FD_CLR(FLAG_SUBNET_LOCALHOST, &el->flags);
FD_CLR(FLAG_SUBNET_PSEUDO_LOCALHOST, &el->flags);
}
if(strncmp(el->ethAddressString, "FF:", 3) == 0) {
/*
The trick below allows me not to duplicate the
"<broadcast>" string in the code
*/
if(hostIpAddress != NULL) {
if(hostIpAddress->hostFamily == AF_INET)
el->hostIp4Address.s_addr = INADDR_BROADCAST;
#ifdef INET6
else if(hostIpAddress->hostFamily == AF_INET6)
el->hostIp6Address = _in6addr_linklocal_allnodes;
#endif
}
FD_SET(FLAG_BROADCAST_HOST, &el->flags);
if(isMulticastAddress(&el->hostIpAddress, &the_local_network, &the_local_network_mask))
FD_SET(FLAG_MULTICAST_HOST, &el->flags);
strncpy(el->hostNumIpAddress,
_addrtostr(&el->hostIpAddress, buf, sizeof(buf)),
strlen(el->hostNumIpAddress));
setResolvedName(el, el->hostNumIpAddress, FLAG_HOST_SYM_ADDR_TYPE_IP);
if((!addrnull(&el->hostIpAddress)) /* 0.0.0.0 */
&& (!addrfull(&el->hostIpAddress)) /* 255.255.255.255 */
&& isBroadcastAddress(&el->hostIpAddress, &the_local_network, &the_local_network_mask)) {
/*
The sender of this packet has obviously a wrong netmask because:
- it is a local host
- it has sent a packet to a broadcast address
- it has not used the FF:FF:FF:FF:FF:FF MAC address
*/
traceEvent(CONST_TRACE_WARNING, "Wrong netmask detected [%s/%s]",
_addrtostr(&el->hostIpAddress, buf, sizeof(buf)),
el->ethAddressString);
}
}
#ifdef DEBUG
{
char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY];
/*
if((strcmp(etheraddr_string(ether_addr, etherbuf), "08:00:20:89:79:D7") == 0)
|| (strcmp(el->hostResolvedName, "more") == 0))
*/
printf("Added a new hash_hostTraffic entry [%s/%s/%s/%d][idx=%d]\n",
etheraddr_string(ether_addr, etherbuf), el->hostResolvedName,
el->hostNumIpAddress, myGlobals.device[actualDeviceId].hostsno, idx);
}
#endif
el->lastSeen = myGlobals.actTime;
if(myGlobals.runningPref.enableSuspiciousPacketDump)
checkSpoofing(el, actualDeviceId);
}
if(hostIpAddress != NULL) {
if(myGlobals.runningPref.dontTrustMACaddr && (ether_addr != NULL))
memcpy(el->lastEthAddress, ether_addr, LEN_ETHERNET_ADDRESS);
addrcpy(&el->hostIpAddress,hostIpAddress);
strncpy(el->hostNumIpAddress,
_addrtostr(hostIpAddress, buf, sizeof(buf)),
sizeof(el->hostNumIpAddress));
if(isBroadcastAddress(&el->hostIpAddress, &the_local_network, &the_local_network_mask)) FD_SET(FLAG_BROADCAST_HOST, &el->flags);
if(isMulticastAddress(&el->hostIpAddress, &the_local_network, &the_local_network_mask)) FD_SET(FLAG_MULTICAST_HOST, &el->flags);
if(isPrivateAddress(hostIpAddress, &the_local_network, &the_local_network_mask)) FD_SET(FLAG_PRIVATE_IP_ADDRESS, &el->flags);
if((ether_addr == NULL) && (isPseudoLocalAddress(hostIpAddress, actualDeviceId, &the_local_network, &the_local_network_mask)))
FD_SET(FLAG_SUBNET_PSEUDO_LOCALHOST, &el->flags);
setResolvedName(el, el->hostNumIpAddress, FLAG_HOST_SYM_ADDR_TYPE_IP);
/* Trick to fill up the address cache */
if(myGlobals.runningPref.numericFlag == 0)
ipaddr2str(el->hostIpAddress, 1);
getHostAS(el);
} else {
/* This is a new entry and hostIpAddress was NOT set. Fill in MAC address, if we have it */
if(symEthName[0] != '\0') {
/* This is a local address so we have the MAC address */
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s%s",
symEthName, &el->ethAddressString[8]);
buf[MAX_LEN_SYM_HOST_NAME-1] = '\0';
setResolvedName(el, buf, FLAG_HOST_SYM_ADDR_TYPE_MAC);
}
}
#ifdef HASH_DEBUG
traceEvent(CONST_TRACE_INFO, "HASH_DEBUG: Adding %s/%s [idx=%d][device=%d]"
"[actualHashSize=%d][#hosts=%d]",
el->ethAddressString, el->hostNumIpAddress, idx, actualDeviceId,
myGlobals.device[actualDeviceId].actualHashSize,
myGlobals.device[actualDeviceId].hostsno);
#endif
setHostSerial(el);
handlePluginHostCreationDeletion(el, (u_short)actualDeviceId, 1 /* host creation */);
}
if(el != NULL) {
el->lastSeen = myGlobals.actTime;
if(setSpoofingFlag)
FD_SET(FLAG_HOST_DUPLICATED_MAC, &el->flags);
#ifdef DEBUG
{
if((hostIpAddress != NULL) && (hostIpAddress->hostFamily == AF_INET6)){
char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY];
traceEvent(CONST_TRACE_INFO, "lookupHost(idx=%d/actualDeviceId=%d) [%s/%s/%s/%d/%d]",
idx, actualDeviceId,
etheraddr_string(ether_addr, etherbuf), el->hostResolvedName,
el->hostNumIpAddress, myGlobals.device[actualDeviceId].hostsno,
useIPAddressForSearching);
}
}
#endif
}
#ifdef DEBUG
if(el == NULL)
traceEvent(CONST_TRACE_INFO, "lookupHost(idx=%d) is NULL", idx);
#endif
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(el);
}
/* ********************************************************** */
HostTraffic *lookupFcHost (FcAddress *hostFcAddress, u_short vsanId,
int actualDeviceId) {
u_int idx;
HostTraffic *el=NULL;
FcNameServerCacheEntry *fcnsEntry;
u_char locked_mutex = 0;
u_short numRuns=0;
u_int hostFound = 0;
if(hostFcAddress == NULL) {
traceEvent(CONST_TRACE_ERROR, "lookupFcHost: Call invoked with NULL"
"FC Address, vsan = %d, device = %d", vsanId,
actualDeviceId);
return(NULL);
}
idx = hashFcHost (hostFcAddress, vsanId, &el, actualDeviceId);
if(el != NULL) {
return (el);
}
else if(idx == FLAG_NO_PEER)
return(NULL);
else {
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
if(el) {
lockHostsHashMutex(el, "lookupFcHost");
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
locked_mutex = 1;
}
}
hostFound = 0; /* This is the same type as the one of HashList */
while(el != NULL) {
if(el->magic != CONST_MAGIC_NUMBER) {
traceEvent(CONST_TRACE_ERROR, "Bad magic number (expected=%d/real=%d) lookupFcHost()",
CONST_MAGIC_NUMBER, el->magic);
break; /* Can't trust this chain ... */
}
if(el->hostTrafficBucket != idx) {
traceEvent(CONST_TRACE_WARNING, "Error: wrong bucketIdx %s/%s (expected=%d/real=%d)",
el->ethAddressString, el->hostNumIpAddress,
idx, el->hostTrafficBucket);
}
if ((el->fcCounters != NULL) &&
(memcmp ((u_int8_t *)&(el->fcCounters->hostFcAddress), hostFcAddress, LEN_FC_ADDRESS) == 0)) {
hostFound = 1;
break;
}
el = el->next;
numRuns++;
}
if(numRuns > myGlobals.device[actualDeviceId].hashListMaxLookups) {
myGlobals.device[actualDeviceId].hashListMaxLookups = numRuns ;
}
if(!hostFound) {
/* New host entry */
if(myGlobals.device[actualDeviceId].hostsno >= myGlobals.runningPref.maxNumHashEntries) {
static char messageShown = 0;
if(!messageShown) {
messageShown = 1;
traceEvent(CONST_TRACE_INFO, "WARNING: Max num hash entries (%u) reached (see -x)",
myGlobals.runningPref.maxNumHashEntries);
}
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
if((el = (HostTraffic*)malloc(sizeof(HostTraffic))) == NULL) {
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
memset(el, 0, sizeof(HostTraffic));
el->firstSeen = myGlobals.actTime;
resetHostsVariables(el);
if(allocFcScsiCounters(el) == NULL) {
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(NULL);
}
el->l2Family = FLAG_HOST_TRAFFIC_AF_FC;
el->fcCounters->devType = SCSI_DEV_UNINIT;
el->magic = CONST_MAGIC_NUMBER;
el->hostTrafficBucket = idx;
el->next = myGlobals.device[actualDeviceId].hash_hostTraffic[el->hostTrafficBucket];
myGlobals.device[actualDeviceId].hash_hostTraffic[el->hostTrafficBucket] = el; /* Insert a new entry */
myGlobals.device[actualDeviceId].hostsno++;
el->fcCounters->hostFcAddress.domain = hostFcAddress->domain;
el->fcCounters->hostFcAddress.area = hostFcAddress->area;
el->fcCounters->hostFcAddress.port = hostFcAddress->port;
safe_snprintf(__FILE__, __LINE__, el->fcCounters->hostNumFcAddress,
sizeof(el->fcCounters->hostNumFcAddress),
fc_to_str ((u_int8_t *)hostFcAddress));
/* TBD: Resolve FC_ID to WWN */
el->fcCounters->vsanId = vsanId;
/* If there is a cache entry, use it */
if((fcnsEntry = findFcHostNSCacheEntry (&el->fcCounters->hostFcAddress, vsanId)) != NULL) {
if(fcnsEntry->alias != NULL)
setResolvedName(el, fcnsEntry->alias, FLAG_HOST_SYM_ADDR_TYPE_FC_ALIAS);
else
setResolvedName(el, (char*)fcnsEntry->pWWN.str, FLAG_HOST_SYM_ADDR_TYPE_FC_WWN);
memcpy (el->fcCounters->pWWN.str, fcnsEntry->pWWN.str, LEN_WWN_ADDRESS);
memcpy (el->fcCounters->nWWN.str, fcnsEntry->nWWN.str, LEN_WWN_ADDRESS);
}
else {
setResolvedName(el, el->fcCounters->hostNumFcAddress, FLAG_HOST_SYM_ADDR_TYPE_FCID);
}
#ifdef HASH_DEBUG
traceEvent(CONST_TRACE_INFO, "HASH_DEBUG: Adding %s/%s [idx=%d][device=%d][actualHashSize=%d][#hosts=%d]",
el->ethAddressString, el->hostNumIpAddress, list->idx, actualDeviceId,
myGlobals.device[actualDeviceId].actualHashSize, myGlobals.device[actualDeviceId].hostsno);
#endif
setHostSerial(el);
}
if(el != NULL) {
el->lastSeen = myGlobals.actTime;
}
if(el == NULL)
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "getHostInfo(idx=%d)(ptr=%p)",
idx, (void*)myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
#ifdef HASH_DEBUG
hashSanityCheck();
#endif
if(locked_mutex) unlockHostsHashMutex(myGlobals.device[actualDeviceId].hash_hostTraffic[idx]);
return(el);
}
/* ************************************ */
#ifdef HASH_DEBUG
static void dumpHash() {
int i=0;
HostTraffic *el;
for(el=getFirstHost(myGlobals.actualReportDeviceId);
el != NULL; el = getNextHost(myGlobals.actualReportDeviceId, el)) {
traceEvent(CONST_TRACE_INFO, "HASH_DEBUG: (%3d) %s / %s [bkt=%d][orig bkt=%d][next=0x%X]",
i++, el->ethAddressString, el->hostNumIpAddress,
el->hostTrafficBucket, el->originalHostTrafficBucket,
el->next);
}
}
/* ***************************************** */
static void hashSanityCheck() {
int i=0;
for(i=FIRST_HOSTS_ENTRY; i<myGlobals.device[0].actualHashSize; i++) {
HostTraffic *el = myGlobals.device[0].hash_hostTraffic[i];
while(el != NULL) {
if(el->hostTrafficBucket != i)
traceEvent(CONST_TRACE_ERROR, "HASH: (%3d) %s / %s [bkt=%d][orig bkt=%d][next=0x%X]",
i, el->ethAddressString, el->hostNumIpAddress,
el->hostTrafficBucket, el->originalHostTrafficBucket,
el->next);
el = el->next;
}
}
}
/* ***************************************** */
static void hostHashSanityCheck(HostTraffic *host) {
int i=0;
for(i=FIRST_HOSTS_ENTRY; i<myGlobals.device[0].actualHashSize; i++) {
HostTraffic *el = myGlobals.device[0].hash_hostTraffic[i];
while(el != NULL) {
if(el == host)
traceEvent(CONST_TRACE_ERROR, "HOST HASH: (%3d) %s / %s [bkt=%d][orig bkt=%d][next=0x%X]",
i, el->ethAddressString, el->hostNumIpAddress,
el->hostTrafficBucket, el->originalHostTrafficBucket,
el->next);
el = el->next;
}
}
}
#endif /* HASH_DEBUG */
/* ******************************
Utility functions used by the remote plugin
****************************** */
#define MAX_NUM_VALID_PTRS 8
static void* valid_ptrs[MAX_NUM_VALID_PTRS] = { NULL };
void add_valid_ptr(void* ptr) {
int i;
traceEvent(CONST_TRACE_INFO, "add_valid_ptr(%p)", ptr);
for(i=0; i<MAX_NUM_VALID_PTRS; i++) {
if(valid_ptrs[i] == NULL) {
valid_ptrs[i] = ptr;
break;
}
}
valid_ptrs[MAX_NUM_VALID_PTRS-1] = ptr;
}
/* ****************************** */
void remove_valid_ptr(void* ptr) {
int i;
for(i=0; i<MAX_NUM_VALID_PTRS; i++) {
if(valid_ptrs[i] == ptr) {
valid_ptrs[i] = NULL;
return;
}
}
/* traceEvent(CONST_TRACE_ERROR, "remove_valid_ptr(%p) failed", ptr); */
}
/* ****************************** */
int is_valid_ptr(void* ptr) {
int i;
for(i=0; i<MAX_NUM_VALID_PTRS; i++) {
if(valid_ptrs[i] == ptr) {
if(i > 0) {
/* Move towards the top */
void *swap = valid_ptrs[i-1];
valid_ptrs[i-1] = valid_ptrs[i];
valid_ptrs[i] = swap;
}
traceEvent(CONST_TRACE_INFO, "is_valid_ptr(%p): 1", ptr);
return(1);
}
}
traceEvent(CONST_TRACE_INFO, "is_valid_ptr(%p): 0", ptr);
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1