2
* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
5
* Copyright (C) 1998-2004 Luca Deri <deri@ntop.org>
7
* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software Foundation,
21
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
/* #define ADDRESS_DEBUG */
34
extern void* perl_alloc();
35
extern void* perl_parse();
36
extern void* perl_get_hv();
37
extern void* perl_get_av();
38
extern void* perl_run();
39
extern void* perl_construct();
40
extern void* perl_destruct();
41
extern void* perl_free();
44
#ifdef CFG_MULTITHREADED
45
static char stateChangeMutexInitialized = 0;
46
static pthread_mutex_t stateChangeMutex;
49
static SessionInfo *passiveSessions;
50
static u_short passiveSessionsLen;
52
static char *versionSite[] = {
53
CONST_VERSIONCHECK_SITE,
54
CONST_VERSIONCHECK_BACKUP_SITE,
57
/* ************************************ */
59
static HostTraffic* _getFirstHost(u_int actualDeviceId, u_int beginIdx) {
62
for(idx=beginIdx; idx<myGlobals.device[actualDeviceId].actualHashSize; idx++) {
63
HostTraffic *el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
66
if(el->magic != CONST_MAGIC_NUMBER) {
67
traceEvent(CONST_TRACE_WARNING, "Error: bad magic number (expected=%d/real=%d)",
68
CONST_MAGIC_NUMBER, el->magic);
78
/* ************************************ */
80
HostTraffic* getFirstHost(u_int actualDeviceId) {
81
return(_getFirstHost(actualDeviceId, FIRST_HOSTS_ENTRY));
84
/* ************************************ */
86
HostTraffic* getNextHost(u_int actualDeviceId, HostTraffic *host) {
87
if(host == NULL) return(NULL);
89
if(host->next != NULL) {
90
if(host->next->magic != CONST_MAGIC_NUMBER) {
91
traceEvent(CONST_TRACE_WARNING, "Error: bad magic number (expected=%d/real=%d)",
92
CONST_MAGIC_NUMBER, host->next->magic);
97
u_int nextIdx = host->hostTrafficBucket+1;
99
if(nextIdx < myGlobals.device[actualDeviceId].actualHashSize)
100
return(_getFirstHost(actualDeviceId, nextIdx));
106
/* ************************************ */
108
HostTraffic* findHostByNumIP(HostAddr hostIpAddress, u_int actualDeviceId) {
111
u_int idx = hashHost(&hostIpAddress, NULL, &dummyShort, &el, actualDeviceId);
114
return(el); /* Found */
115
else if(idx == FLAG_NO_PEER)
118
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
120
for(; el != NULL; el = el->next) {
121
if((el->hostNumIpAddress != NULL) && (addrcmp(&el->hostIpAddress,&hostIpAddress) == 0))
128
probably a local host has been searched using an IP
129
address (we should have used a MAC)
132
for(idx=0; idx<myGlobals.device[actualDeviceId].actualHashSize; idx++) {
133
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
135
for(; el != NULL; el = el->next) {
136
if((el->hostNumIpAddress != NULL) && (addrcmp(&el->hostIpAddress,&hostIpAddress) == 0))
145
traceEvent(CONST_TRACE_NOISY, "==>>> Unable to locate host %s",
146
_intoa(hostIpAddress, buf, sizeof(buf)));
153
/* ************************************ */
155
HostTraffic* findHostBySerial(HostSerial theSerial, u_int actualDeviceId) {
156
if(theSerial.serialType == SERIAL_IPV4 || theSerial.serialType == SERIAL_IPV6) {
157
return(findHostByNumIP(theSerial.value.ipAddress, actualDeviceId));
160
return(findHostByMAC(theSerial.value.ethAddress, actualDeviceId));
164
/* ************************************ */
166
HostTraffic* findHostByMAC(char* macAddr, u_int actualDeviceId) {
168
short dummyShort = 0;
169
u_int idx = hashHost(NULL, macAddr, &dummyShort, &el, actualDeviceId);
172
return(el); /* Found */
173
else if(idx == FLAG_NO_PEER)
176
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
178
for(; el != NULL; el = el->next) {
179
if((el->ethAddress[0] != '\0') && (!strncmp(el->ethAddress, macAddr, LEN_ETHERNET_ADDRESS)))
186
/* *****************************************************/
189
unsigned long in6_hash(struct in6_addr *addr) {
191
(addr->s6_addr[13] ) | (addr->s6_addr[15] << 8) |
192
(addr->s6_addr[14] << 16) | (addr->s6_addr[11] << 24);
197
/* *************************************** */
199
unsigned short computeIdx(HostAddr *srcAddr, HostAddr *dstAddr, int sport, int dport) {
202
if (srcAddr->hostFamily != dstAddr->hostFamily)
204
switch (srcAddr->hostFamily){
207
* The hash key has to be calculated in a specular
208
* way: its value has to be the same regardless
209
* of the flow direction.
211
* Patch on the line below courtesy of
212
* Paul Chapman <pchapman@fury.bio.dfo.ca>
214
idx = (u_int)(dstAddr->Ip4Address.s_addr+srcAddr->Ip4Address.s_addr+sport+dport) ;
218
idx = (u_int)(dstAddr->Ip6Address.s6_addr[0] +
219
dstAddr->Ip6Address.s6_addr[0] +
220
srcAddr->Ip6Address.s6_addr[0] +
221
srcAddr->Ip6Address.s6_addr[0] + sport +! dport);
228
/* ******************************************** */
230
u_int16_t computeTransId(HostAddr *srcAddr, HostAddr *dstAddr, int sport, int dport) {
231
u_int16_t transactionId;
232
if (srcAddr->hostFamily != dstAddr->hostFamily)
234
switch (srcAddr->hostFamily){
236
transactionId = (u_int16_t)(3*srcAddr->Ip4Address.s_addr+
237
dstAddr->Ip4Address.s_addr+5*dport+7*sport);
241
transactionId = (u_int16_t)(3*srcAddr->Ip6Address.s6_addr[0]+
242
dstAddr->Ip6Address.s6_addr[0]+5*dport+7*sport);
246
return transactionId;
249
/* ***************************** */
252
int in6_isglobal(struct in6_addr *addr) {
253
return (addr->s6_addr[0] & 0xe0) == 0x20;
257
/* ***************************** */
259
short addrcmp(HostAddr *addr1, HostAddr *addr2) {
266
else if(addr2 == NULL)
269
if(addr1->hostFamily == 0)
270
if(addr2->hostFamily == 0)
274
else if(addr2->hostFamily == 0)
277
if(addr1->hostFamily != addr2->hostFamily)
278
if(addr1->hostFamily > addr2->hostFamily)
283
switch (addr1->hostFamily){
285
if (addr1->Ip4Address.s_addr > addr2->Ip4Address.s_addr)
287
else if (addr1->Ip4Address.s_addr < addr2->Ip4Address.s_addr)
291
/*return (addr1->Ip4Address.s_addr != addr2->Ip4Address.s_addr);*/
295
if(memcmp(&addr1->Ip6Address,&addr2->Ip6Address,sizeof(struct in6_addr)) > 0)
297
else if (memcmp(&addr1->Ip6Address,&addr2->Ip6Address,sizeof(struct in6_addr)) <0)
308
/* ****************************************** */
310
HostAddr *addrcpy(HostAddr *dst, HostAddr *src) {
311
dst->hostFamily = src->hostFamily;
312
switch (src->hostFamily){
314
return memcpy(&dst->Ip4Address,&src->Ip4Address,sizeof(struct in_addr));
317
return memcpy(&dst->Ip6Address,&src->Ip6Address,sizeof(struct in6_addr));
325
/* ****************************************** */
327
int addrinit(HostAddr *addr) {
328
addr->hostFamily = AF_INET;
329
addr->Ip4Address.s_addr = 0;
333
/* ****************************************** */
335
unsigned short addrget(HostAddr *Haddr,void *addr, int *family , int *size) {
336
struct in_addr v4addr;
338
*family = Haddr->hostFamily;
339
switch(Haddr->hostFamily){
341
v4addr.s_addr = ntohl(Haddr->Ip4Address.s_addr);
342
memcpy((struct in_addr *)addr,&v4addr,sizeof(struct in_addr));
343
*size = sizeof(struct in_addr);
347
memcpy((struct in6_addr *)addr,&Haddr->Ip6Address, sizeof(struct in6_addr));
348
*size = sizeof(struct in6_addr);
355
/* ****************************************** */
357
unsigned short addrput(int family, HostAddr *dst, void *src) {
360
dst->hostFamily = family;
363
memcpy(&dst->Ip4Address, (struct in_addr *)src,sizeof(struct in_addr));
367
memcpy(&dst->Ip6Address, (struct in6_addr *)src, sizeof(struct in6_addr));
374
/* ****************************************** */
376
unsigned short addrnull(HostAddr *addr) {
377
switch(addr->hostFamily){
379
return (addr->Ip4Address.s_addr == 0x0);
382
return (addr->Ip6Address.s6_addr[0] == 0x0);
389
/* ****************************************** */
391
unsigned short addrfull(HostAddr *addr) {
392
switch(addr->hostFamily){
394
return (addr->Ip4Address.s_addr == 0xffffffff);
403
/* ****************************************** */
406
unsigned short prefixlookup(struct in6_addr *addr, NtopIfaceAddr *addrs, int size) {
410
for (it = addrs ; it != NULL; it = it->next){
412
size = it->af.inet6.prefixlen / 8;
415
char buf[47], buf1[47];
416
traceEvent(CONST_TRACE_INFO, "DEBUG: comparing [%s/%s]: %d",
417
_intop(addr, buf, INET6_ADDRSTRLEN),
418
_intop(&it->af.inet6.ifAddr, buf1, INET6_ADDRSTRLEN), found);
421
if (memcmp(&it->af.inet6.ifAddr,addr,size) == 0){
431
/* ****************************************** */
434
unsigned short addrlookup(struct in6_addr *addr, NtopIfaceAddr *addrs) {
435
return (prefixlookup(addr,addrs, sizeof(struct in6_addr)));
439
/* ****************************************** */
442
NtopIfaceAddr *getLocalHostAddressv6(NtopIfaceAddr *addrs, char* device) {
443
struct iface_handler *ih;
445
struct iface_addr *ia;
446
NtopIfaceAddr *tmp = NULL;
449
if(!(ih = iface_new()))
452
for(ii = iface_getif_first(ih) ; ii ; ii = iface_getif_next(ii))
453
if(!strcmp(ii->name,device))
454
if(iface_if_getinfo(ii) & IFACE_INFO_UP) {
455
/* Allocate memory for IPv6 addresses*/
456
count = iface_if_addrcount(ii, AF_INET6);
457
addrs = (NtopIfaceAddr *)calloc(count, sizeof(NtopIfaceAddr));
459
for(ia = iface_getaddr_first(ii, AF_INET6) ; ia ;
460
ia = iface_getaddr_next(ia, AF_INET6)) {
461
struct iface_addr_inet6 i6;
462
iface_addr_getinfo(ia, &i6);
463
if(in6_isglobal(&i6.addr)&& (addr_pos < count)) {
464
tmp = &addrs[addr_pos];
465
tmp->family = AF_INET6;
466
memcpy(&tmp->af.inet6.ifAddr, &i6.addr,sizeof(struct in6_addr));
467
tmp->af.inet6.prefixlen = ia->af.inet6.prefixlen;
468
tmp->next = &addrs[addr_pos+1];
474
if(tmp != NULL) tmp->next = NULL;
477
traceEvent(CONST_TRACE_INFO, "DEBUG: Local address is: %s", intop(hostAddress));
484
/*******************************************/
486
* Copy arg vector into a new buffer, concatenating arguments with spaces.
488
char* copy_argv(register char **argv) {
490
register u_int len = 0;
499
len += strlen(*p++) + 1;
501
buf = (char*)malloc(len);
503
traceEvent(CONST_TRACE_FATALERROR, "Insufficient memory for copy_argv");
509
while ((src = *p++) != NULL) {
510
while ((*dst++ = *src++) != '\0')
519
/**************************************/
522
unsigned short isLinkLocalAddress(struct in6_addr *addr) {
527
else if(addr->s6_addr == 0x0)
528
return 0; /* IP-less myGlobals.device (is it trying to boot via DHCP/BOOTP ?) */
530
for(i=0; i<myGlobals.numDevices; i++)
531
if(IN6_IS_ADDR_LINKLOCAL(addr)) {
533
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is a linklocal address", intop(addr));
542
/*******************************************/
545
unsigned short in6_isMulticastAddress(struct in6_addr *addr) {
546
if(IN6_IS_ADDR_MULTICAST(addr)) {
548
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is multicast [%X/%X]",
557
/*******************************************/
560
unsigned short in6_isLocalAddress(struct in6_addr *addr, u_int deviceId) {
561
if(deviceId >= myGlobals.numDevices) {
562
traceEvent(CONST_TRACE_WARNING, "Index %u out of range [0..%u] - address treated as remote",
563
deviceId, myGlobals.numDevices);
567
if(addrlookup(addr,myGlobals.device[deviceId].v6Addrs) == 1) {
569
traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intop(addr));
574
if(myGlobals.trackOnlyLocalHosts)
578
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is %s", intop(addr));
580
/* Link Local Addresses are local */
581
return(isLinkLocalAddress(addr));
584
/* ******************************************* */
586
unsigned short in6_isPrivateAddress(struct in6_addr *addr) {
587
/* IPv6 have private addresses ?*/
592
/* ********************************* */
594
unsigned short in_isBroadcastAddress(struct in_addr *addr) {
599
else if(addr->s_addr == 0x0)
600
return 0; /* IP-less myGlobals.device (is it trying to boot via DHCP/BOOTP ?) */
602
for(i=0; i<myGlobals.numDevices; i++) {
603
if(!myGlobals.device[i].virtualDevice) {
604
if(myGlobals.device[i].netmask.s_addr == 0xFFFFFFFF) /* PPP */
606
else if(((addr->s_addr | myGlobals.device[i].netmask.s_addr) == addr->s_addr)
607
|| ((addr->s_addr & 0x000000FF) == 0x000000FF)
608
|| ((addr->s_addr & 0x000000FF) == 0x00000000) /* Network address */
611
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is a broadcast address", intoa(*addr));
618
return(in_isPseudoBroadcastAddress(addr));
622
/* ********************************* */
624
unsigned short in_isMulticastAddress(struct in_addr *addr) {
625
if((addr->s_addr & CONST_MULTICAST_MASK) == CONST_MULTICAST_MASK) {
627
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is multicast [%X/%X]",
629
((unsigned long)(addr->s_addr) & CONST_MULTICAST_MASK),
638
/* ********************************* */
640
unsigned short in_isLocalAddress(struct in_addr *addr, u_int deviceId) {
641
if(deviceId >= myGlobals.numDevices) {
642
traceEvent(CONST_TRACE_WARNING, "Index %u out of range [0..%u] - address treated as remote",
643
deviceId, myGlobals.numDevices);
648
traceEvent(CONST_TRACE_INFO, "Address: %s", intoa(*addr));
649
traceEvent(CONST_TRACE_INFO, "Network: %s", intoa(myGlobals.device[deviceId].network));
650
traceEvent(CONST_TRACE_INFO, "NetMask: %s", intoa(myGlobals.device[deviceId].netmask));
653
if(addr == NULL) return(0);
655
if(!myGlobals.mergeInterfaces) {
656
if((addr->s_addr & myGlobals.device[deviceId].netmask.s_addr) == myGlobals.device[deviceId].network.s_addr) {
658
traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intoa(*addr));
665
for(i=0; i<myGlobals.numDevices; i++)
666
if((addr->s_addr & myGlobals.device[i].netmask.s_addr) == myGlobals.device[i].network.s_addr) {
668
traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intoa(*addr));
674
if(myGlobals.trackOnlyLocalHosts)
678
traceEvent(CONST_TRACE_INFO, "DEBUG: %s is %s", intoa(*addr),
679
isBroadcastAddress(addr) ? "pseudolocal" : "remote");
681
/* Broadcast is considered a local address */
682
return(in_isBroadcastAddress(addr));
685
/* ********************************* */
687
unsigned short in_isPrivateAddress(struct in_addr *addr) {
688
/* See http://www.isi.edu/in-notes/rfc1918.txt */
690
/* Fixes below courtesy of Wies-Software <wies@wiessoft.de> */
691
if(((addr->s_addr & 0xFF000000) == 0x0A000000) /* 10/8 */
692
|| ((addr->s_addr & 0xFFF00000) == 0xAC100000) /* 172.16/12 */
693
|| ((addr->s_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168/16 */
700
/***************************************/
702
unsigned short isBroadcastAddress(HostAddr *addr){
703
switch(addr->hostFamily){
705
return (in_isBroadcastAddress(&addr->Ip4Address));
708
return (isLinkLocalAddress(&addr->Ip6Address));
714
/* ******************************************** */
716
unsigned short isMulticastAddress(HostAddr *addr){
717
switch(addr->hostFamily){
719
return (in_isMulticastAddress(&addr->Ip4Address));
722
return (in6_isMulticastAddress(&addr->Ip6Address));
728
/* ************************************************* */
730
unsigned short isLocalAddress(HostAddr *addr, u_int deviceId) {
731
switch(addr->hostFamily){
733
return (in_isLocalAddress(&addr->Ip4Address, deviceId));
736
return (in6_isLocalAddress(&addr->Ip6Address, deviceId));
742
/* ************************************************** */
744
unsigned short isPrivateAddress(HostAddr *addr) {
745
switch(addr->hostFamily){
747
return (in_isPrivateAddress(&addr->Ip4Address));
750
return (in6_isPrivateAddress(&addr->Ip6Address));
757
/* **********************************************
761
* It converts an integer in the range
762
* from 0 to 255 in number of bits
763
* useful for netmask calculation.
764
* The conmyGlobals.version is valid if there
765
* is an uninterrupted sequence of
766
* bits set to 1 at the most signi-
767
* ficant positions. Example:
770
* 1110 1000 -> invalid
773
* 0 - 8 (number of subsequent
775
* -1 (CONST_INVALIDNETMASK)
778
* Courtesy of Antonello Maiorca <marty@tai.it>
780
*********************************************** */
782
static int int2bits(int number) {
786
if((number > 255) || (number < 0))
789
traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, CONST_INVALIDNETMASK);
791
return(CONST_INVALIDNETMASK);
795
test = ~number & 0xff;
801
if(number != ((~(0xff >> bits)) & 0xff))
804
traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, CONST_INVALIDNETMASK);
806
return(CONST_INVALIDNETMASK);
811
traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, bits);
818
/* ***********************************************
822
* Converts a dotted quad notation
823
* netmask specification to the
824
* equivalent number of bits.
825
* from 0 to 255 in number of bits
826
* useful for netmask calculation.
827
* The converion is valid if there
828
* is an uninterrupted sequence of
829
* bits set to 1 at the most signi-
830
* ficant positions. Example:
833
* 1110 1000 -> invalid
836
* 0 - 32 (number of subsequent
838
* -1 (CONST_INVALIDNETMASK)
841
* Courtesy of Antonello Maiorca <marty@tai.it>
843
*********************************************** */
845
int dotted2bits(char *mask) {
847
int fields_num, field_bits;
851
fields_num = sscanf(mask, "%d.%d.%d.%d",
852
&fields[0], &fields[1], &fields[2], &fields[3]);
853
if((fields_num == 1) && (fields[0] <= 32) && (fields[0] >= 0))
856
traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%s) = %d", mask, fields[0]);
860
for (i=0; i < fields_num; i++)
862
/* We are in a dotted quad notation. */
863
field_bits = int2bits (fields[i]);
866
case CONST_INVALIDNETMASK:
867
return(CONST_INVALIDNETMASK);
870
/* whenever a 0 bits field is reached there are no more */
873
traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%15s) = %d", mask, bits);
875
/* In this case we are in a bits (not dotted quad) notation */
876
return(bits /* fields[0] - L.Deri 08/2001 */);
883
traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%15s) = %d", mask, bits);
888
/* ********************************* */
890
/* Example: "131.114.0.0/16,193.43.104.0/255.255.255.0" */
892
void handleAddressLists(char* addresses, u_int32_t theNetworks[MAX_NUM_NETWORKS][3],
893
u_short *numNetworks, char *localAddresses,
894
int localAddressesLen, int flagWhat) {
895
char *strtokState, *address;
896
int laBufferPosition = 0, laBufferUsed = 0, i;
898
if((addresses == NULL) || (addresses[0] == '\0'))
901
traceEvent(CONST_TRACE_NOISY,
902
"Processing %s parameter '%s'",
903
flagWhat == CONST_HANDLEADDRESSLISTS_MAIN ? "-m | --local-subnets" :
904
flagWhat == CONST_HANDLEADDRESSLISTS_RRD ? "RRD" :
905
flagWhat == CONST_HANDLEADDRESSLISTS_NETFLOW ? "Netflow white/black list" : "unknown",
908
memset(localAddresses, 0, localAddressesLen);
910
address = strtok_r(addresses, ",", &strtokState);
912
while(address != NULL) {
913
char *mask = strchr(address, '/');
916
if (flagWhat == CONST_HANDLEADDRESSLISTS_MAIN)
917
traceEvent(CONST_TRACE_WARNING, "-m: Empty mask '%s' - ignoring entry", address);
919
u_int32_t network, networkMask, broadcast;
920
int bits, a, b, c, d;
924
bits = dotted2bits (mask);
926
if(sscanf(address, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) {
927
traceEvent(CONST_TRACE_WARNING, "%s: Bad format '%s' - ignoring entry",
928
flagWhat == CONST_HANDLEADDRESSLISTS_MAIN ? "-m" :
929
flagWhat == CONST_HANDLEADDRESSLISTS_RRD ? "RRD" :
930
flagWhat == CONST_HANDLEADDRESSLISTS_NETFLOW ? "Netflow" : "unknown",
932
address = strtok_r(NULL, ",", &strtokState);
936
if(bits == CONST_INVALIDNETMASK) {
937
/* malformed netmask specification */
938
traceEvent(CONST_TRACE_WARNING, "%s: Net mask '%s' not valid - ignoring entry",
939
flagWhat == CONST_HANDLEADDRESSLISTS_MAIN ? "-m | --local-subnets" :
940
flagWhat == CONST_HANDLEADDRESSLISTS_RRD ? "RRD" :
941
flagWhat == CONST_HANDLEADDRESSLISTS_NETFLOW ? "Netflow white/black list" : "unknown",
943
address = strtok_r(NULL, ",", &strtokState);
947
network = ((a & 0xff) << 24) + ((b & 0xff) << 16) + ((c & 0xff) << 8) + (d & 0xff);
948
/* Special case the /32 mask - yeah, we could probably do it with some fancy
949
u long long stuff, but this is simpler...
950
Burton Strauss <Burton@ntopsupport.com> Jun2002
953
networkMask = 0xffffffff;
955
networkMask = 0xffffffff >> bits;
956
networkMask = ~networkMask;
960
traceEvent(CONST_TRACE_INFO, "DEBUG: Nw=%08X - Mask: %08X [%08X]",
961
network, networkMask, (network & networkMask));
964
if((networkMask >= 0xFFFFFF00) /* Courtesy of Roy-Magne Mo <romo@interpost.no> */
965
&& ((network & networkMask) != network)) {
966
/* malformed network specification */
967
traceEvent(CONST_TRACE_WARNING, "%s: %d.%d.%d.%d/%d is not a valid network - correcting mask",
968
flagWhat == CONST_HANDLEADDRESSLISTS_MAIN ? "-m | --local-subnets" :
969
flagWhat == CONST_HANDLEADDRESSLISTS_RRD ? "RRD" :
970
flagWhat == CONST_HANDLEADDRESSLISTS_NETFLOW ? "Netflow white/black list" : "unknown",
973
/* correcting network numbers as specified in the netmask */
974
network &= networkMask;
976
a = (int) ((network >> 24) & 0xff);
977
b = (int) ((network >> 16) & 0xff);
978
c = (int) ((network >> 8) & 0xff);
979
d = (int) ((network >> 0) & 0xff);
981
traceEvent(CONST_TRACE_NOISY, "Assuming %d.%d.%d.%d/%d [0x%08x/0x%08x]",
982
a, b, c, d, bits, network, networkMask);
985
traceEvent(CONST_TRACE_INFO, "DEBUG: %d.%d.%d.%d/%d [0x%08x/0x%08x]",
986
a, b, c, d, bits, network, networkMask);
989
broadcast = network | (~networkMask);
992
a = (int) ((broadcast >> 24) & 0xff);
993
b = (int) ((broadcast >> 16) & 0xff);
994
c = (int) ((broadcast >> 8) & 0xff);
995
d = (int) ((broadcast >> 0) & 0xff);
997
traceEvent(CONST_TRACE_INFO, "DEBUG: Broadcast: [net=0x%08x] [broadcast=%d.%d.%d.%d]",
998
network, a, b, c, d);
1001
if((*numNetworks) < MAX_NUM_NETWORKS) {
1003
/* If this is the real list, we check against the actual network addresses
1004
* and warn the user of superfluous entries - for the other lists, rrd and netflow
1005
* the local address is valid, it's NOT assumed.
1007
if (flagWhat == CONST_HANDLEADDRESSLISTS_MAIN) {
1008
for(i=0; i<myGlobals.numDevices; i++) {
1009
if((network == myGlobals.device[i].network.s_addr) &&
1010
(myGlobals.device[i].netmask.s_addr == networkMask)) {
1011
a = (int) ((network >> 24) & 0xff);
1012
b = (int) ((network >> 16) & 0xff);
1013
c = (int) ((network >> 8) & 0xff);
1014
d = (int) ((network >> 0) & 0xff);
1016
traceEvent(CONST_TRACE_INFO,
1017
"-m: Discarded unnecessary parameter %d.%d.%d.%d/%d - this is the local network",
1025
theNetworks[(*numNetworks)][CONST_NETWORK_ENTRY] = network;
1026
theNetworks[(*numNetworks)][CONST_NETMASK_ENTRY] = networkMask;
1027
theNetworks[(*numNetworks)][CONST_BROADCAST_ENTRY] = broadcast;
1029
a = (int) ((network >> 24) & 0xff);
1030
b = (int) ((network >> 16) & 0xff);
1031
c = (int) ((network >> 8) & 0xff);
1032
d = (int) ((network >> 0) & 0xff);
1034
if ((laBufferUsed = snprintf(&localAddresses[laBufferPosition],
1037
(*numNetworks) == 0 ? "" : ", ",
1042
laBufferPosition += laBufferUsed;
1043
localAddressesLen -= laBufferUsed;
1049
a = (int) ((network >> 24) & 0xff);
1050
b = (int) ((network >> 16) & 0xff);
1051
c = (int) ((network >> 8) & 0xff);
1052
d = (int) ((network >> 0) & 0xff);
1054
traceEvent(CONST_TRACE_ERROR, "%s: %d.%d.%d.%d/%d - Too many networks (limit %d) - discarded",
1055
flagWhat == CONST_HANDLEADDRESSLISTS_MAIN ? "-m" :
1056
flagWhat == CONST_HANDLEADDRESSLISTS_RRD ? "RRD" :
1057
flagWhat == CONST_HANDLEADDRESSLISTS_NETFLOW ? "Netflow" : "unknown",
1063
address = strtok_r(NULL, ",", &strtokState);
1067
/* ********************************* */
1069
void handleLocalAddresses(char* addresses) {
1070
char localAddresses[1024];
1072
localAddresses[0] = '\0';
1074
handleAddressLists(addresses, myGlobals.localNetworks, &myGlobals.numLocalNetworks,
1075
localAddresses, sizeof(localAddresses), CONST_HANDLEADDRESSLISTS_MAIN);
1077
/* Not used anymore */
1078
if(myGlobals.localAddresses != NULL) free(myGlobals.localAddresses);
1080
if(localAddresses[0] != '\0')
1081
myGlobals.localAddresses = strdup(localAddresses);
1084
/* ********************************* */
1087
unsigned short in6_pseudoLocalAddress(struct in6_addr *addr) {
1090
for(i=0; i<myGlobals.numDevices; i++) {
1091
if (prefixlookup(addr,myGlobals.device[i].v6Addrs,0) == 1)
1099
unsigned short __pseudoLocalAddress(struct in_addr *addr,
1100
u_int32_t theNetworks[MAX_NUM_NETWORKS][3],
1101
u_short numNetworks) {
1104
for(i=0; i<numNetworks; i++) {
1105
#ifdef ADDRESS_DEBUG
1106
char buf[32], buf1[32], buf2[32];
1107
struct in_addr addr1, addr2;
1109
addr1.s_addr = theNetworks[i][CONST_NETWORK_ENTRY];
1110
addr2.s_addr = theNetworks[i][CONST_NETMASK_ENTRY];
1112
traceEvent(CONST_TRACE_INFO, "DEBUG: %s comparing [%s/%s]",
1113
_intoa(*addr, buf, sizeof(buf)),
1114
_intoa(addr1, buf1, sizeof(buf1)),
1115
_intoa(addr2, buf2, sizeof(buf2)));
1117
if((addr->s_addr & theNetworks[i][CONST_NETMASK_ENTRY]) == theNetworks[i][CONST_NETWORK_ENTRY]) {
1118
#ifdef ADDRESS_DEBUG
1119
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is pseudolocal", intoa(*addr));
1123
#ifdef ADDRESS_DEBUG
1124
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is NOT pseudolocal", intoa(*addr));
1132
/* ********************************* */
1134
unsigned short in_pseudoLocalAddress(struct in_addr *addr) {
1135
return(__pseudoLocalAddress(addr, myGlobals.localNetworks, myGlobals.numLocalNetworks));
1138
/* ********************************* */
1141
unsigned short in6_deviceLocalAddress(struct in6_addr *addr, u_int deviceId) {
1144
if(addrlookup(addr,myGlobals.device[deviceId].v6Addrs))
1153
/* ********************************* */
1155
unsigned short in_deviceLocalAddress(struct in_addr *addr, u_int deviceId) {
1158
if((addr->s_addr & myGlobals.device[deviceId].netmask.s_addr) == myGlobals.device[deviceId].network.s_addr)
1165
char buf[32], buf1[32];
1166
traceEvent(CONST_TRACE_INFO, "DEBUG: comparing [%s/%s]: %d",
1167
_intoa(*addr, buf, sizeof(buf)),
1168
_intoa(myGlobals.device[deviceId].network, buf1, sizeof(buf1)), rc);
1175
/* ********************************* */
1178
unsigned short in6_isPseudoLocalAddress(struct in6_addr *addr, u_int deviceId) {
1181
i = in6_isLocalAddress(addr, deviceId);
1184
#ifdef ADDRESS_DEBUG
1185
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is local", intop(addr));
1188
return 1; /* This is a real local address */
1191
if(in6_pseudoLocalAddress(addr))
1195
We don't check for broadcast as this check has been
1196
performed already by isLocalAddress() just called
1199
#ifdef ADDRESS_DEBUG
1200
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is remote", intop(addr));
1207
/* ******************************************** */
1209
/* This function returns true when a host is considered local
1210
as specified using the 'm' flag */
1211
unsigned short in_isPseudoLocalAddress(struct in_addr *addr, u_int deviceId) {
1214
i = in_isLocalAddress(addr, deviceId);
1217
#ifdef ADDRESS_DEBUG
1218
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is local", intoa(*addr));
1221
return 1; /* This is a real local address */
1224
if(in_pseudoLocalAddress(addr))
1228
We don't check for broadcast as this check has been
1229
performed already by isLocalAddress() just called
1232
#ifdef ADDRESS_DEBUG
1233
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s [deviceId=%d] is remote",
1234
intoa(*addr), deviceId);
1240
/* ********************************* */
1242
/* This function returns true when an address is the broadcast
1243
for the specified (-m flag subnets */
1245
unsigned short in_isPseudoBroadcastAddress(struct in_addr *addr) {
1248
#ifdef ADDRESS_DEBUG
1249
traceEvent(CONST_TRACE_WARNING, "DEBUG: Checking %8X (pseudo broadcast)", addr->s_addr);
1252
for(i=0; i<myGlobals.numLocalNetworks; i++) {
1253
if(addr->s_addr == myGlobals.localNetworks[i][CONST_BROADCAST_ENTRY]) {
1254
#ifdef ADDRESS_DEBUG
1255
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: --> %8X is pseudo broadcast", addr->s_addr);
1259
#ifdef ADDRESS_DEBUG
1261
traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %8X is NOT pseudo broadcast", addr->s_addr);
1268
/*************************************/
1270
unsigned short deviceLocalAddress(HostAddr *addr, u_int deviceId) {
1271
switch(addr->hostFamily){
1273
return (in_deviceLocalAddress(&addr->Ip4Address, deviceId));
1276
return (in6_deviceLocalAddress(&addr->Ip6Address, deviceId));
1282
/* ********************************* */
1284
unsigned short isPseudoLocalAddress(HostAddr *addr, u_int deviceId) {
1285
switch(addr->hostFamily){
1287
return (in_isPseudoLocalAddress(&addr->Ip4Address, deviceId));
1290
return (in6_isPseudoLocalAddress(&addr->Ip6Address, deviceId));
1296
/* ********************************* */
1298
unsigned short isPseudoBroadcastAddress(HostAddr *addr) {
1299
switch(addr->hostFamily){
1301
return (in_isPseudoBroadcastAddress(&addr->Ip4Address));
1310
/* ********************************* */
1312
unsigned short _pseudoLocalAddress(HostAddr *addr) {
1313
switch(addr->hostFamily){
1315
return (in_pseudoLocalAddress(&addr->Ip4Address));
1318
return (in6_pseudoLocalAddress(&addr->Ip6Address));
1324
/* ********************************* */
1327
* Returns the difference between gmt and local time in seconds.
1328
* Use gmtime() and localtime() to keep things simple.
1329
* [Borrowed from tcpdump]
1331
int32_t gmt2local(time_t t) {
1333
struct tm *gmt, *myloc;
1340
myloc = localtime_r(&t, &loc);
1342
dt = (myloc->tm_hour - gmt->tm_hour)*60*60+(myloc->tm_min - gmt->tm_min)*60;
1345
* If the year or julian day is different, we span 00:00 GMT
1346
* and must add or subtract a day. Check the year first to
1347
* avoid problems when the julian day wraps.
1349
dir = myloc->tm_year - gmt->tm_year;
1351
dir = myloc->tm_yday - gmt->tm_yday;
1352
dt += dir * 24 * 60 * 60;
1357
/* ********************************* */
1359
char *dotToSlash(char *name) {
1361
* Convert a dotted quad ip address name a.b.c.d to a/b/c/d or a\b\c\d
1366
localBuffer = strdup(name);
1368
for (i=0; i<strlen(localBuffer); i++) {
1369
if((localBuffer[i] == '.') || (localBuffer[i] == ':'))
1371
localBuffer[i]='\\';
1377
localBuffer[i]='\0';
1381
/* ********************************* */
1383
/* Example: "flow1='host jake',flow2='dst host born2run'" */
1384
void handleFlowsSpecs(void) {
1386
char *flow, *buffer=NULL, *strtokState, *flows;
1388
flows = myGlobals.flowSpecs;
1390
if((!flows) || (!flows[0]))
1393
fd = fopen(flows, "rb");
1396
flow = strtok_r(flows, ",", &strtokState);
1401
if(stat(flows, &buf) != 0) {
1403
traceEvent(CONST_TRACE_INFO, "Error while stat() of %s", flows);
1405
/* Not used anymore */
1406
free(myGlobals.flowSpecs);
1407
myGlobals.flowSpecs = strdup("Error reading file");
1411
buffer = (char*)malloc(buf.st_size+8) /* just to be safe */;
1413
for(i=0;i<buf.st_size;) {
1414
len = fread(&buffer[i], sizeof(char), buf.st_size-i, fd);
1421
/* remove trailing carriage return */
1422
if(buffer[strlen(buffer)-1] == '\n')
1423
buffer[strlen(buffer)-1] = 0;
1425
flow = strtok_r(buffer, ",", &strtokState);
1428
while(flow != NULL) {
1429
char *flowSpec = strchr(flow, '=');
1431
if(flowSpec == NULL)
1432
traceEvent(CONST_TRACE_INFO, "Missing flow spec '%s'. It has been ignored.", flow);
1434
struct bpf_program fcode;
1436
char *flowName = flow;
1440
/* flowSpec should now point to 'host jake' */
1441
len = strlen(flowSpec);
1444
|| (flowSpec[0] != '\'')
1445
|| (flowSpec[len-1] != '\''))
1446
traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (missing \'). "
1447
"It has been ignored.", flowSpec);
1449
flowSpec[len-1] = '\0';
1452
traceEvent(CONST_TRACE_NOISY, "Compiling flow specification '%s'", flowSpec);
1454
rc = pcap_compile(myGlobals.device[0].pcapPtr, &fcode, flowSpec, 1, myGlobals.device[0].netmask.s_addr);
1457
traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (syntax error). "
1458
"It has been ignored.", flowSpec);
1460
FlowFilterList *newFlow;
1462
#ifdef HAVE_PCAP_FREECODE
1463
pcap_freecode(&fcode);
1465
newFlow = (FlowFilterList*)calloc(1, sizeof(FlowFilterList));
1467
if(newFlow == NULL) {
1468
traceEvent(CONST_TRACE_INFO, "Fatal error: not enough memory. Bye!");
1469
if(buffer != NULL) free(buffer);
1474
newFlow->fcode = (struct bpf_program*)calloc(myGlobals.numDevices, sizeof(struct bpf_program));
1476
for(i=0; i<myGlobals.numDevices; i++) {
1477
rc = pcap_compile(myGlobals.device[i].pcapPtr, &newFlow->fcode[i],
1478
flowSpec, 1, myGlobals.device[i].netmask.s_addr);
1481
traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (syntax error). "
1482
"It has been ignored.", flowSpec);
1485
/* Not used anymore */
1486
free(myGlobals.flowSpecs);
1487
myGlobals.flowSpecs = strdup("Error, wrong flow specification");
1492
newFlow->flowName = strdup(flowName);
1493
newFlow->pluginStatus.activePlugin = 1;
1494
newFlow->pluginStatus.pluginPtr = NULL; /* Added by Jacques Le Rest <jlerest@ifremer.fr> */
1495
newFlow->next = myGlobals.flowsList;
1496
myGlobals.flowsList = newFlow;
1502
flow = strtok_r(NULL, ",", &strtokState);
1510
/* ********************************* */
1512
int getLocalHostAddress(struct in_addr *hostAddress, char* device) {
1515
hostAddress->s_addr = GetHostIPAddr();
1519
struct sockaddr_in *sinAddr;
1525
fd = socket(AF_INET, SOCK_DGRAM, 0);
1527
traceEvent(CONST_TRACE_INFO, "socket error: %d", errno);
1531
memset(&ifr, 0, sizeof(ifr));
1534
/* XXX Work around Linux kernel bug */
1535
ifr.ifr_addr.sa_family = AF_INET;
1537
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
1538
if(ioctl(fd, SIOCGIFADDR, (char*)&ifr) < 0) {
1540
traceEvent(CONST_TRACE_INFO, "DEBUG: SIOCGIFADDR error: %s/errno=%d", device, errno);
1544
sinAddr = (struct sockaddr_in *)&ifr.ifr_addr;
1546
if((hostAddress->s_addr = ntohl(sinAddr->sin_addr.s_addr)) == 0)
1551
traceEvent(CONST_TRACE_INFO, "DEBUG: Local address is: %s", intoa(*hostAddress));
1554
/* ******************************* */
1560
if(ioctl(fd, SIOCGIFNETMASK, (char*)&ifr) >= 0) {
1561
sinAddr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
1562
numHosts = 0xFFFFFFFF - ntohl(sinAddr->sin_addr.s_addr)+1;
1564
numHosts = 256; /* default C class */
1566
traceEvent(CONST_TRACE_INFO, "DEBUG: Num subnet hosts: %d", numHosts);
1570
/* ******************************* */
1578
/* ********************************* */
1581
#ifdef CFG_MULTITHREADED
1583
/* *********** MULTITHREAD STUFF *********** */
1585
int createThread(pthread_t *threadId,
1586
void *(*__start_routine) (void *),
1590
rc = pthread_create(threadId, NULL, __start_routine, userParm);
1593
traceEvent(CONST_TRACE_NOISY, "createThread(0x%x), rc = %s(%d)",
1594
threadId, strerror(rc), rc);
1595
myGlobals.numThreads++;
1599
/* ************************************ */
1601
int killThread(pthread_t *threadId) {
1603
rc = pthread_detach(*threadId);
1606
traceEvent(CONST_TRACE_NOISY, "killThread(0x%x), rc = %s(%d)",
1607
threadId, strerror(rc), rc);
1609
myGlobals.numThreads--;
1613
/* ************************************ */
1615
int _createMutex(PthreadMutex *mutexId, char* fileName, int fileLine) {
1618
if(!stateChangeMutexInitialized) {
1619
pthread_mutex_init(&stateChangeMutex, NULL);
1620
stateChangeMutexInitialized = 1;
1623
memset(mutexId, 0, sizeof(PthreadMutex));
1625
rc = pthread_mutex_init(&(mutexId->mutex), NULL);
1628
traceEvent(CONST_TRACE_ERROR,
1629
"createMutex() call returned %d(%d) [%s:%d]",
1630
rc, errno, fileName, fileLine);
1632
mutexId->isInitialized = 1;
1633
#ifdef SEMAPHORE_DEBUG
1634
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: createMutex() succeeded [0x%X@%s:%d]",
1635
(void*)&(mutexId->mutex), fileName, fileLine);
1642
/* ************************************ */
1644
void _deleteMutex(PthreadMutex *mutexId, char* fileName, int fileLine) {
1647
if(mutexId == NULL) {
1648
if(myGlobals.endNtop == 0)
1649
traceEvent(CONST_TRACE_ERROR,
1650
"deleteMutex() called with a NULL mutex [%s:%d]",
1651
fileName, fileLine);
1655
if(!mutexId->isInitialized) {
1656
if(myGlobals.endNtop == 0)
1657
traceEvent(CONST_TRACE_ERROR,
1658
"deleteMutex() called with an UN-INITIALIZED mutex [0x%X@%s:%d]",
1659
(void*)&(mutexId->mutex), fileName, fileLine);
1663
rc = pthread_mutex_unlock(&(mutexId->mutex));
1664
#ifdef SEMAPHORE_DEBUG
1665
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: deleteMutex() unlock (rc=%d) [0x%X@%s:%d]",
1666
rc, (void*)&(mutexId->mutex), fileName, fileLine);
1668
rc = pthread_mutex_destroy(&(mutexId->mutex));
1669
#ifdef SEMAPHORE_DEBUG
1670
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: deleteMutex() destroy (rc=%d) [0x%X@%s:%d]",
1671
rc, (void*)&(mutexId->mutex), fileName, fileLine);
1674
memset(mutexId, 0, sizeof(PthreadMutex));
1677
/* ************************************ */
1679
int _accessMutex(PthreadMutex *mutexId, char* where,
1680
char* fileName, int fileLine) {
1684
if(mutexId == NULL) {
1685
if(myGlobals.endNtop == 0)
1686
traceEvent(CONST_TRACE_ERROR,
1687
"accessMutex() called with a NULL mutex [%s:%d]",
1688
fileName, fileLine);
1692
if(!mutexId->isInitialized) {
1693
if(myGlobals.endNtop == 0)
1694
traceEvent(CONST_TRACE_ERROR,
1695
"accessMutex() called '%s' with an UN-INITIALIZED mutex [0x%X@%s:%d]",
1696
where, (void*)&(mutexId->mutex), fileName, fileLine);
1700
#ifdef SEMAPHORE_DEBUG
1701
/* Do not move this code below -
1702
* we want to keep the unprotected field updates
1703
* as close to the trylock as possible!
1705
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: accessMutex() called '%s' [0x%X@%s:%d]",
1706
where, (void*)&(mutexId->mutex), fileName, fileLine);
1709
if(!myGlobals.disableMutexExtraInfo) {
1711
if(mutexId->isLocked) {
1712
if((fileLine == mutexId->lockLine)
1713
&& (strcmp(fileName, mutexId->lockFile) == 0)
1714
&& (myPid == mutexId->lockPid)
1715
&& (pthread_equal(mutexId->lockThread, pthread_self()))) {
1716
traceEvent(CONST_TRACE_WARNING,
1717
"accessMutex() called '%s' with a self-LOCKED mutex [0x%X@%s:%d]",
1718
where, (void*)&(mutexId->mutex), fileName, fileLine);
1722
strcpy(mutexId->lockAttemptFile, fileName);
1723
mutexId->lockAttemptLine=fileLine;
1724
mutexId->lockAttemptPid=myPid;
1727
rc = pthread_mutex_lock(&(mutexId->mutex));
1729
pthread_mutex_lock(&stateChangeMutex);
1730
if(!myGlobals.disableMutexExtraInfo) {
1731
mutexId->lockAttemptFile[0] = '\0';
1732
mutexId->lockAttemptLine=0;
1733
mutexId->lockAttemptPid=(pid_t) 0;
1734
mutexId->lockThread=pthread_self();
1738
traceEvent(CONST_TRACE_ERROR, "accessMutex() call '%s' failed (rc=%d) [0x%X@%s:%d]",
1739
where, rc, (void*)&(mutexId->mutex), fileName, fileLine);
1742
#ifdef SEMAPHORE_DEBUG
1743
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: accessMutex() call '%s' succeeded [0x%X@%s:%d]",
1744
where, (void*)&(mutexId->mutex), fileName, fileLine);
1747
mutexId->numLocks++;
1748
mutexId->isLocked = 1;
1749
if(!myGlobals.disableMutexExtraInfo) {
1750
mutexId->lockTime = time(NULL);
1751
mutexId->lockPid = myPid;
1752
if(fileName != NULL) {
1753
strcpy(mutexId->lockFile, fileName);
1754
mutexId->lockLine = fileLine;
1757
strcpy(mutexId->where, where);
1761
pthread_mutex_unlock(&stateChangeMutex);
1766
/* ************************************ */
1768
int _tryLockMutex(PthreadMutex *mutexId, char* where,
1769
char* fileName, int fileLine) {
1773
if(mutexId == NULL) {
1774
if(myGlobals.endNtop == 0)
1775
traceEvent(CONST_TRACE_ERROR,
1776
"tryLockMutex() called '%s' with a NULL mutex [%s:%d]",
1777
where, fileName, fileLine);
1781
if(!mutexId->isInitialized) {
1782
if(myGlobals.endNtop == 0)
1783
traceEvent(CONST_TRACE_ERROR,
1784
"tryLockMutex() called '%s' with an UN-INITIALIZED mutex [0x%X@%s:%d]",
1785
where, (void*)&(mutexId->mutex), fileName, fileLine);
1789
#ifdef SEMAPHORE_DEBUG
1790
/* Do not move this code below -
1791
* we want to keep the unprotected field updates
1792
* as close to the trylock as possible!
1794
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: tryLockMutex() call '%s' called [0x%X@%s:%d]",
1795
where, (void*)&(mutexId->mutex), fileName, fileLine);
1798
if(!myGlobals.disableMutexExtraInfo) {
1800
if(mutexId->isLocked) {
1801
if((strcmp(fileName, mutexId->lockFile) == 0)
1802
&& (fileLine == mutexId->lockLine)
1803
&& (myPid == mutexId->lockPid)
1804
&& (pthread_equal(mutexId->lockThread, pthread_self()))
1806
traceEvent(CONST_TRACE_WARNING,
1807
"tryLockMutex() called '%s' with a self-LOCKED mutex [0x%X@%s:%d]",
1808
where, (void*)&(mutexId->mutex), fileName, fileLine);
1812
strcpy(mutexId->lockAttemptFile, fileName);
1813
mutexId->lockAttemptLine=fileLine;
1814
mutexId->lockAttemptPid=myPid;
1822
EBUSY (mutex already locked)
1824
rc = pthread_mutex_trylock(&(mutexId->mutex));
1825
pthread_mutex_lock(&stateChangeMutex);
1826
if(!myGlobals.disableMutexExtraInfo) {
1827
mutexId->lockAttemptFile[0] = '\0';
1828
mutexId->lockAttemptLine = 0;
1829
mutexId->lockAttemptPid = (pid_t) 0;
1833
#ifdef SEMAPHORE_DEBUG
1834
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: tryLockMutex() call '%s' failed (rc=%d) [0x%X@%s:%d]",
1835
where, rc, (void*)&(mutexId->mutex), fileName, fileLine);
1838
#ifdef SEMAPHORE_DEBUG
1839
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: tryLockMutex() call '%s' succeeded [0x%X@%s:%d]",
1840
where, (void*)&(mutexId->mutex), fileName, fileLine);
1843
mutexId->numLocks++;
1844
mutexId->isLocked = 1;
1845
if(!myGlobals.disableMutexExtraInfo) {
1846
mutexId->lockTime = time(NULL);
1847
mutexId->lockPid = myPid;
1848
mutexId->lockThread = pthread_self();
1850
if(fileName != NULL) {
1851
strcpy(mutexId->lockFile, fileName);
1852
mutexId->lockLine = fileLine;
1855
if(where != NULL) strcpy(mutexId->where, where);
1859
pthread_mutex_unlock(&stateChangeMutex);
1863
/* ************************************ */
1865
int _isMutexLocked(PthreadMutex *mutexId, char* fileName, int fileLine) {
1868
if(mutexId == NULL) {
1869
if(myGlobals.endNtop == 0)
1870
traceEvent(CONST_TRACE_ERROR,
1871
"isMutexLocked() called with a NULL mutex [%s:%d]",
1872
fileName, fileLine);
1876
if(!mutexId->isInitialized) {
1877
if(myGlobals.endNtop == 0)
1878
traceEvent(CONST_TRACE_ERROR,
1879
"isMutexLocked() called with an UN-INITIALIZED mutex [0x%X@%s:%d]",
1880
(void*)&(mutexId->mutex), fileName, fileLine);
1884
#ifdef SEMAPHORE_DEBUG
1885
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: isMutexLocked() testing [0x%X@%s:%d]",
1886
(void*)&(mutexId->mutex), fileName, fileLine);
1889
rc = pthread_mutex_trylock(&(mutexId->mutex));
1895
EBUSY (mutex already locked)
1899
pthread_mutex_unlock(&(mutexId->mutex));
1905
/* ************************************ */
1907
int _releaseMutex(PthreadMutex *mutexId,
1908
char* fileName, int fileLine) {
1911
if(mutexId == NULL) {
1912
if(myGlobals.endNtop == 0)
1913
traceEvent(CONST_TRACE_ERROR,
1914
"releaseMutex() called with a NULL mutex [%s:%d]",
1915
fileName, fileLine);
1919
if(!mutexId->isInitialized) {
1920
if(myGlobals.endNtop == 0)
1921
traceEvent(CONST_TRACE_ERROR,
1922
"releaseMutex() called with an UN-INITIALIZED mutex [0x%X@%s:%d]",
1923
(void*)&(mutexId->mutex), fileName, fileLine);
1927
pthread_mutex_lock(&stateChangeMutex);
1929
if(!mutexId->isLocked) {
1930
traceEvent(CONST_TRACE_WARNING,
1931
"releaseMutex() called with an UN-LOCKED mutex [0x%X@%s:%d] last unlock [pid %d, %s:%d]",
1932
(void*)&(mutexId->mutex), fileName, fileLine,
1933
mutexId->unlockPid, mutexId->unlockFile, mutexId->unlockLine);
1937
#ifdef SEMAPHORE_DEBUG
1938
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: releaseMutex() releasing [0x%X@%s:%d]",
1939
(void*)&(mutexId->mutex), fileName, fileLine);
1941
rc = pthread_mutex_unlock(&(mutexId->mutex));
1944
traceEvent(CONST_TRACE_ERROR, "releaseMutex() failed (rc=%d) [0x%X@%s:%d]",
1945
rc, (void*)&(mutexId->mutex), fileName, fileLine);
1947
if(!myGlobals.disableMutexExtraInfo) {
1948
time_t lockDuration = time(NULL) - mutexId->lockTime;
1950
if((mutexId->maxLockedDuration < lockDuration)
1951
|| (mutexId->maxLockedDurationUnlockLine == 0 /* Never set */)) {
1952
mutexId->maxLockedDuration = lockDuration;
1954
if(fileName != NULL) {
1955
strcpy(mutexId->maxLockedDurationUnlockFile, fileName);
1956
mutexId->maxLockedDurationUnlockLine = fileLine;
1959
#ifdef SEMAPHORE_DEBUG
1960
if(mutexId->maxLockedDuration > 0) {
1961
traceEvent(CONST_TRACE_INFO,
1962
"SEMAPHORE_DEBUG: releaseMutex() was locked for maximum, %d secs [0x%X@%s:%d]",
1963
mutexId->maxLockedDuration,
1964
(void*)&(mutexId->mutex),
1965
fileName, fileLine);
1971
mutexId->isLocked = 0;
1972
mutexId->numReleases++;
1973
if(!myGlobals.disableMutexExtraInfo) {
1974
mutexId->unlockPid=getpid();
1975
if(fileName != NULL) {
1976
strcpy(mutexId->unlockFile, fileName);
1977
mutexId->unlockLine = fileLine;
1982
pthread_mutex_unlock(&stateChangeMutex);
1984
#ifdef SEMAPHORE_DEBUG
1986
traceEvent(CONST_TRACE_WARNING, "SEMAPHORE_DEBUG: releaseMutex() failed (rc=%d) [0x%X@%s:%d]",
1987
(void*)&(mutexId->mutex), rc, fileName, fileLine);
1989
traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: releaseMutex() succeeded [0x%X@%s:%d]",
1990
(void*)&(mutexId->mutex), fileName, fileLine);
1995
/* ************************************ */
1997
int createCondvar(ConditionalVariable *condvarId) {
2000
rc = pthread_mutex_init(&condvarId->mutex, NULL);
2001
rc = pthread_cond_init(&condvarId->condvar, NULL);
2002
condvarId->predicate = 0;
2007
/* ************************************ */
2009
void deleteCondvar(ConditionalVariable *condvarId) {
2010
pthread_mutex_destroy(&condvarId->mutex);
2011
pthread_cond_destroy(&condvarId->condvar);
2014
/* ************************************ */
2016
int waitCondvar(ConditionalVariable *condvarId) {
2019
if((rc = pthread_mutex_lock(&condvarId->mutex)) != 0)
2022
while(condvarId->predicate <= 0) {
2023
rc = pthread_cond_wait(&condvarId->condvar, &condvarId->mutex);
2026
condvarId->predicate--;
2028
rc = pthread_mutex_unlock(&condvarId->mutex);
2033
/* ************************************ */
2035
int timedwaitCondvar(ConditionalVariable *condvarId, struct timespec *expiration) {
2038
if((rc = pthread_mutex_lock(&condvarId->mutex)) != 0)
2041
while(condvarId->predicate <= 0) {
2042
rc = pthread_cond_timedwait(&condvarId->condvar, &condvarId->mutex, expiration);
2043
if (rc == ETIMEDOUT) {
2048
condvarId->predicate--;
2050
rc = pthread_mutex_unlock(&condvarId->mutex);
2055
/* ************************************ */
2057
int signalCondvar(ConditionalVariable *condvarId) {
2060
rc = pthread_mutex_lock(&condvarId->mutex);
2062
condvarId->predicate++;
2064
rc = pthread_mutex_unlock(&condvarId->mutex);
2065
rc = pthread_cond_signal(&condvarId->condvar);
2070
/* ************************************ */
2072
#ifdef HAVE_SEMAPHORE_H
2074
int createSem(sem_t *semId, int initialValue) {
2077
rc = sem_init(semId, 0, initialValue);
2081
/* ************************************ */
2083
void waitSem(sem_t *semId) {
2084
int rc = sem_wait(semId);
2086
if((rc != 0) && (errno != 4 /* Interrupted system call */))
2087
traceEvent(CONST_TRACE_INFO, "waitSem failed [errno=%d/%s]", errno, strerror(errno));
2090
/* ************************************ */
2092
int incrementSem(sem_t *semId) {
2093
return(sem_post(semId));
2096
/* ************************************ */
2098
* WARNING: Enabling semaphors will probably cause bugs!
2101
int decrementSem(sem_t *semId) {
2102
return(sem_trywait(semId));
2105
/* ************************************ */
2107
int deleteSem(sem_t *semId) {
2108
return(sem_destroy(semId));
2112
#endif /* CFG_MULTITHREADED */
2115
/* ************************************ */
2117
int checkCommand(char* commandName) {
2121
char buf[256], *workBuf;
2122
struct stat statBuf;
2124
FILE* fd = popen(commandName, "r");
2127
traceEvent(CONST_TRACE_ERROR,
2128
"External tool test failed(code=%d). Disabling %s function (popen failed).",
2138
traceEvent(CONST_TRACE_ERROR,
2139
"External tool test failed(code=%d20). Disabling %s function (tool won't run).",
2145
/* ok, it can be run ... is it suid? */
2148
"which %s 2>/dev/null",
2154
fd = popen(buf, "r");
2156
workBuf = fgets(buf, sizeof(buf), fd);
2158
if(workBuf != NULL) {
2159
workBuf = strchr(buf, '\n');
2160
if(workBuf != NULL) workBuf[0] = '\0';
2161
rc = stat(buf, &statBuf);
2163
if ((statBuf.st_mode & (S_IROTH | S_IXOTH) ) == (S_IROTH | S_IXOTH) ) {
2164
if ((statBuf.st_mode & (S_ISUID | S_ISGID) ) != 0) {
2165
traceEvent(CONST_TRACE_ERROR,
2166
"External tool %s is suid root. FYI: This is good for ntop, but could be dangerous for the system!",
2185
/* test failed ... */
2186
traceEvent(CONST_TRACE_ERROR,
2187
"External tool test failed(code=%d%d%d). Disabling %s function%s.",
2192
ecode == 7 ? " (tool exists but is not suid root)" : "");
2198
/* ************************************ */
2200
char* decodeNBstring(char* theString, char *theBuffer) {
2201
int i=0, j = 0, len=strlen(theString);
2203
while((i<len) && (theString[i] != '\0')) {
2204
char encodedChar, decodedChar;
2206
encodedChar = theString[i++];
2207
if((encodedChar < 'A') || (encodedChar > 'Z')) break; /* Wrong character */
2210
decodedChar = encodedChar << 4;
2212
encodedChar = theString[i++];
2213
if((encodedChar < 'A') || (encodedChar > 'Z')) break; /* Wrong character */
2216
decodedChar |= encodedChar;
2218
theBuffer[j++] = decodedChar;
2221
theBuffer[j] = '\0';
2224
theBuffer[i] = (char)tolower(theBuffer[i]);
2229
/* ************************************ */
2231
char* savestr(const char *str)
2235
static char *strptr = NULL;
2236
static u_int strsize = 0;
2238
size = strlen(str) + 1;
2239
if(size > strsize) {
2243
strptr = (char*)malloc(strsize);
2244
if(strptr == NULL) {
2245
fprintf(stderr, "savestr: malloc\n");
2249
(void)strncpy(strptr, str, strsize);
2257
/* ************************************ */
2259
/* The function below has been inherited by tcpdump */
2262
int name_interpret(char *in, char *out, int numBytes) {
2267
/* traceEvent(CONST_TRACE_WARNING, "name_interpret error (numBytes=%d)", numBytes); */
2275
if(len > 30 || len < 1) {
2276
/* traceEvent(CONST_TRACE_WARNING, "name_interpret error (numBytes=%d)", numBytes); */
2281
if(in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
2286
*out = ((in[0]-'A')<<4) + (in[1]-'A');
2293
/* Courtesy of Roberto F. De Luca <deluca@tandar.cnea.gov.ar> */
2294
/* Trim trailing whitespace from the returned string */
2295
for(out--; out>=b && *out==' '; out--) *out = '\0';
2301
/* ******************************* */
2303
char* getNwInterfaceType(int i) {
2304
switch(myGlobals.device[i].datalink) {
2305
case DLT_NULL: return("No link-layer encapsulation");
2306
case DLT_EN10MB: return("Ethernet");
2307
case DLT_EN3MB: return("Experimental Ethernet (3Mb)");
2308
case DLT_AX25: return("Amateur Radio AX.25");
2309
case DLT_PRONET: return("Proteon ProNET Token Ring");
2310
case DLT_CHAOS: return("Chaos");
2311
case DLT_IEEE802: return("IEEE 802 Networks");
2312
case DLT_ARCNET: return("ARCNET");
2313
case DLT_SLIP: return("SLIP");
2314
case DLT_PPP: return("PPP");
2315
case DLT_FDDI: return("FDDI");
2316
case DLT_ATM_RFC1483: return("LLC/SNAP encapsulated ATM");
2317
case DLT_RAW: return("Raw IP");
2318
case DLT_SLIP_BSDOS: return("BSD/OS SLIP");
2319
case DLT_PPP_BSDOS: return("BSD/OS PPP");
2322
return(""); /* NOTREACHED (I hope) */
2325
/* ************************************ */
2327
int getActualInterface(u_int deviceId) {
2328
if(myGlobals.mergeInterfaces) {
2329
return(myGlobals.device[0].dummyDevice == 0 ? 0 : deviceId);
2334
/* ************************************ */
2336
void resetHostsVariables(HostTraffic* el) {
2337
FD_ZERO(&(el->flags));
2339
el->totContactedSentPeers = el->totContactedRcvdPeers = 0;
2340
resetUsageCounter(&el->contactedSentPeers);
2341
resetUsageCounter(&el->contactedRcvdPeers);
2342
resetUsageCounter(&el->contactedRouters);
2346
if (el->dnsDomainValue != NULL) free(el->dnsDomainValue);
2347
el->dnsDomainValue = NULL;
2348
if (el->dnsTLDValue != NULL) free(el->dnsTLDValue);
2349
el->dnsTLDValue = NULL;
2350
if (el->ip2ccValue != NULL) free(el->ip2ccValue);
2351
el->ip2ccValue = NULL;
2352
el->hostResolvedName[0] = '\0';
2353
el->hostResolvedNameType = FLAG_HOST_SYM_ADDR_TYPE_NONE;
2354
if (el->fingerprint != NULL) free(el->fingerprint);
2355
el->fingerprint = NULL;
2356
if (el->nonIPTraffic != NULL) free(el->nonIPTraffic);
2357
el->nonIPTraffic = NULL;
2358
if (el->routedTraffic != NULL) free(el->routedTraffic);
2359
el->routedTraffic = NULL;
2360
if (el->portsUsage != NULL) free(el->portsUsage);
2361
el->portsUsage = NULL;
2362
if (el->protoIPTrafficInfos != NULL) free(el->protoIPTrafficInfos);
2363
el->protoIPTrafficInfos = NULL;
2364
if (el->icmpInfo != NULL) free(el->icmpInfo);
2365
el->icmpInfo = NULL;
2366
if (el->protocolInfo != NULL) free(el->protocolInfo);
2367
el->protocolInfo = NULL;
2370
resetUsageCounter(&el->contactedSentPeers);
2371
resetUsageCounter(&el->contactedRcvdPeers);
2372
resetUsageCounter(&el->contactedRouters);
2374
memset(el->recentlyUsedClientPorts, -1, sizeof(int)*MAX_NUM_RECENT_PORTS);
2375
memset(el->recentlyUsedServerPorts, -1, sizeof(int)*MAX_NUM_RECENT_PORTS);
2376
memset(el->otherIpPortsRcvd, -1, sizeof(int)*MAX_NUM_RECENT_PORTS);
2377
memset(el->otherIpPortsSent, -1, sizeof(int)*MAX_NUM_RECENT_PORTS);
2379
if (el->secHostPkts != NULL) free(el->secHostPkts);
2380
el->secHostPkts = NULL;
2383
/* ************************************
2385
* [Borrowed from tcpdump]
2388
u_short in_cksum(const u_short *addr, int len, u_short csum) {
2390
const u_short *w = addr;
2395
* Our algorithm is simple, using a 32 bit accumulator (sum),
2396
* we add sequential 16 bit words to it, and at the end, fold
2397
* back all the carry bits from the top 16 bits into the lower
2405
sum += htons(*(u_char *)w<<8);
2408
* add back carry outs from top 16 bits to low 16 bits
2410
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
2411
sum += (sum >> 16); /* add carry */
2412
answer = ~sum; /* truncate to 16 bits */
2416
/* ****************** */
2418
void addTimeMapping(u_int16_t transactionId,
2419
struct timeval theTime) {
2421
u_int idx = transactionId % CONST_NUM_TRANSACTION_ENTRIES;
2425
traceEvent(CONST_TRACE_INFO, "DEBUG: addTimeMapping(0x%X)", transactionId);
2427
for(i=0; i<CONST_NUM_TRANSACTION_ENTRIES; i++) {
2428
if(myGlobals.transTimeHash[idx].transactionId == 0) {
2429
myGlobals.transTimeHash[idx].transactionId = transactionId;
2430
myGlobals.transTimeHash[idx].theTime = theTime;
2432
} else if(myGlobals.transTimeHash[idx].transactionId == transactionId) {
2433
myGlobals.transTimeHash[idx].theTime = theTime;
2437
idx = (idx+1) % CONST_NUM_TRANSACTION_ENTRIES;
2441
/* ****************** */
2444
* The time difference in microseconds
2446
long delta_time (struct timeval * now,
2447
struct timeval * before) {
2448
time_t delta_seconds;
2449
time_t delta_microseconds;
2452
* compute delta in second, 1/10's and 1/1000's second units
2454
delta_seconds = now -> tv_sec - before -> tv_sec;
2455
delta_microseconds = now -> tv_usec - before -> tv_usec;
2457
if(delta_microseconds < 0) {
2458
/* manually carry a one from the seconds field */
2459
delta_microseconds += 1000000; /* 1e6 */
2463
return((delta_seconds * 1000000) + delta_microseconds);
2466
/* ****************** */
2468
time_t getTimeMapping(u_int16_t transactionId,
2469
struct timeval theTime) {
2471
u_int idx = transactionId % CONST_NUM_TRANSACTION_ENTRIES;
2475
traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X)", transactionId);
2478
/* ****************************************
2480
As Andreas Pfaller <apfaller@yahoo.com.au>
2481
pointed out, the hash code needs to be optimised.
2482
Actually the hash is scanned completely
2483
if (unlikely but possible) the searched entry
2484
is not present into the table.
2486
**************************************** */
2488
for(i=0; i<CONST_NUM_TRANSACTION_ENTRIES; i++) {
2489
if(myGlobals.transTimeHash[idx].transactionId == transactionId) {
2490
time_t msDiff = (time_t)delta_time(&theTime, &myGlobals.transTimeHash[idx].theTime);
2491
myGlobals.transTimeHash[idx].transactionId = 0; /* Free bucket */
2493
traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X) [diff=%d]",
2494
transactionId, (unsigned long)msDiff);
2499
idx = (idx+1) % CONST_NUM_TRANSACTION_ENTRIES;
2503
traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X) [not found]", transactionId);
2505
return(0); /* Not found */
2508
/* ********************************** */
2510
void traceEvent(int eventTraceLevel, char* file,
2511
int line, char * format, ...) {
2513
va_start (va_ap, format);
2515
/* Fix courtesy of "Burton M. Strauss III" <BStrauss@acm.org> */
2516
if(eventTraceLevel <= myGlobals.traceLevel) {
2517
time_t theTime = time(NULL);
2519
char bufTime[LEN_TIMEFORMAT_BUFFER];
2520
char buf[LEN_GENERAL_WORK_BUFFER];
2521
char bufMsg[LEN_GENERAL_WORK_BUFFER];
2522
char bufMsgID[LEN_MEDIUM_WORK_BUFFER];
2523
char bufLineID[LEN_MEDIUM_WORK_BUFFER];
2528
/* First we prepare the various fields */
2530
/* Message time, used for printf() - remember, syslog() does it's own time stamp */
2531
memset(bufTime, 0, sizeof(bufTime));
2532
strftime(bufTime, sizeof(bufTime), CONST_LOCALE_TIMESPEC, localtime_r(&theTime, &t));
2534
/* The file/line or 'MSGID' tag, depends on logExtra */
2535
memset(bufMsgID, 0, sizeof(bufMsgID));
2537
if(myGlobals.traceLevel > CONST_NOISY_TRACE_LEVEL) {
2538
mFile = strdup(file);
2540
for(beginFileIdx=strlen(mFile)-1; beginFileIdx>0; beginFileIdx--) {
2541
if(mFile[beginFileIdx] == '.') mFile[beginFileIdx] = '\0'; /* Strip off .c */
2543
if(mFile[beginFileIdx-1] == '\\') break; /* Start after \ (Win32) */
2545
if(mFile[beginFileIdx-1] == '/') break; /* Start after / (!Win32) */
2549
if(myGlobals.traceLevel >= CONST_DETAIL_TRACE_LEVEL) {
2550
unsigned int messageid = 0;
2553
if(snprintf(bufLineID, sizeof(bufLineID), "[%s:%d] ", &mFile[beginFileIdx], line) < 0)
2556
/* Hash the message format into an id */
2557
for (i=0; i<=strlen(format); i++) {
2558
messageid = (messageid << 1) ^ max(0,format[i]-32);
2561
/* 1st chars of file name for uniqueness */
2562
messageid += (file[0]-32) * 256 + file[1]-32;
2563
if(snprintf(bufMsgID, sizeof(bufMsgID), "[MSGID%07d]", (messageid & 0x8fffff)) < 0)
2570
/* Now we use the variable functions to 'print' the user's message */
2571
memset(bufMsg, 0, sizeof(bufMsg));
2572
vsnprintf(bufMsg, sizeof(bufMsg), format, va_ap);
2573
/* Strip a trailing return from bufMsg */
2574
if(bufMsg[strlen(bufMsg)-1] == '\n')
2575
bufMsg[strlen(bufMsg)-1] = 0;
2577
/* Second we prepare the complete log message into buf
2579
memset(buf, 0, sizeof(buf));
2580
if(snprintf(buf, sizeof(buf), "%s %s %s%s%s",
2582
(myGlobals.traceLevel >= CONST_DETAIL_TRACE_LEVEL) ? bufMsgID : "",
2583
(myGlobals.traceLevel > CONST_DETAIL_TRACE_LEVEL) ? bufLineID : "",
2584
eventTraceLevel == CONST_FATALERROR_TRACE_LEVEL ? "**FATAL_ERROR** " :
2585
eventTraceLevel == CONST_ERROR_TRACE_LEVEL ? "**ERROR** " :
2586
eventTraceLevel == CONST_WARNING_TRACE_LEVEL ? "**WARNING** " : "",
2591
/* Finished preparing message fields */
2593
/* So, (INFO & above only) - post it to logView buffer. */
2594
if ((eventTraceLevel <= CONST_INFO_TRACE_LEVEL) &&
2595
(myGlobals.logView != NULL)) {
2597
#ifdef CFG_MULTITHREADED
2599
if(myGlobals.logViewMutex.isInitialized)
2600
pthread_mutex_lock(&myGlobals.logViewMutex.mutex);
2604
if (myGlobals.logView[myGlobals.logViewNext] != NULL)
2605
free(myGlobals.logView[myGlobals.logViewNext]);
2607
myGlobals.logView[myGlobals.logViewNext] = strdup(buf);
2609
myGlobals.logViewNext = (myGlobals.logViewNext + 1) % CONST_LOG_VIEW_BUFFER_SIZE;
2611
#ifdef CFG_MULTITHREADED
2613
if(myGlobals.logViewMutex.isInitialized)
2614
pthread_mutex_unlock(&myGlobals.logViewMutex.mutex);
2620
/* If ntop is a Win32 service, we're done - we don't (yet) write to the
2621
* windows event logs and there's no console...
2624
if(isNtopAservice) return;
2627
/* Otherwise, we have two paths -
2628
* Win32/no syslog headers/syslog not enabled via -L run time switch
2630
* Not Win32, Have syslog headers and enabled via -L run time switch
2634
#ifdef MAKE_WITH_SYSLOG
2635
if(myGlobals.useSyslog == FLAG_SYSLOG_NONE) {
2638
printf("%s\n", buf);
2641
#ifdef MAKE_WITH_SYSLOG
2643
/* Skip over time - syslog() adds it automatically) */
2644
char *bufLog = &buf[strlen(bufTime)];
2646
/* SYSLOG and set */
2647
openlog("ntop", LOG_PID, myGlobals.useSyslog);
2649
/* syslog(..) call fix courtesy of Peter Suschlik <peter@zilium.de> */
2650
#ifdef MAKE_WITH_LOG_XXXXXX
2651
switch(myGlobals.traceLevel) {
2652
case CONST_FATALERROR_TRACE_LEVEL:
2653
case CONST_ERROR_TRACE_LEVEL:
2654
syslog(LOG_ERR, "%s", bufLog);
2656
case CONST_WARNING_TRACE_LEVEL:
2657
syslog(LOG_WARNING, "%s", bufLog);
2659
case CONST_ALWAYSDISPLAY_TRACE_LEVEL:
2660
syslog(LOG_NOTICE, "%s", bufLog);
2663
syslog(LOG_INFO, "%s", bufLog);
2667
syslog(LOG_ERR, "%s", bufLog);
2671
#endif /* MAKE_WITH_SYSLOG */
2678
/* ******************************************** */
2680
char* _strncpy(char *dest, const char *src, size_t n) {
2681
size_t len = strlen(src);
2686
memcpy(dest, src, len);
2691
/* ******************************************** */
2693
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
2694
#ifndef HAVE_STRTOK_R
2695
/* Reentrant string tokenizer. Generic myGlobals.version.
2697
Slightly modified from: glibc 2.1.3
2699
Copyright (C) 1991, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
2700
This file is part of the GNU C Library.
2702
The GNU C Library is free software; you can redistribute it and/or
2703
modify it under the terms of the GNU Library General Public License as
2704
published by the Free Software Foundation; either version 2 of the
2705
License, or (at your option) any later version.
2707
The GNU C Library is distributed in the hope that it will be useful,
2708
but WITHOUT ANY WARRANTY; without even the implied warranty of
2709
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2710
Library General Public License for more details.
2712
You should have received a copy of the GNU Library General Public
2713
License along with the GNU C Library; see the file COPYING.LIB. If not,
2714
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2715
Boston, MA 02111-1307, USA. */
2717
char *strtok_r(char *s, const char *delim, char **save_ptr) {
2723
/* Scan leading delimiters. */
2724
s += strspn (s, delim);
2728
/* Find the end of the token. */
2730
s = strpbrk (token, delim);
2732
/* This token finishes the string. */
2735
/* Terminate the token and make *SAVE_PTR point past it. */
2744
/* ********************************** */
2746
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
2748
int getSniffedDNSName(char *hostNumIpAddress,
2749
char *name, int maxNameLen) {
2754
if((hostNumIpAddress[0] != '\0') && myGlobals.dnsCacheFile) {
2758
key.dptr = hostNumIpAddress;
2759
key.dsize = strlen(key.dptr)+1;
2761
data = gdbm_fetch(myGlobals.dnsCacheFile, key);
2763
if(data.dptr != NULL) {
2764
xstrncpy(name, data.dptr, maxNameLen);
2773
/* ******************************** */
2775
char *strtolower(char *s) {
2784
/* ******************************** */
2786
* xstrncpy() - similar to strncpy(3) but terminates string always with
2787
* '\0' if (n != 0 and dst != NULL), and doesn't do padding
2789
char *xstrncpy(char *dest, const char *src, size_t n) {
2794
while (--n != 0 && *src != '\0')
2800
/* *************************************** */
2802
int strOnlyDigits(const char *s) {
2807
while ((*s) != '\0') {
2816
/* ****************************************************** */
2818
FILE* getNewRandomFile(char* fileName, int len) {
2825
/* Patch courtesy of Thomas Biege <thomas@suse.de> */
2826
if(((tmpfd = mkstemp(fileName)) < 0)
2827
|| (fchmod(tmpfd, 0600) < 0)
2828
|| ((fd = fdopen(tmpfd, "wb")) == NULL))
2831
char tmpFileName[NAME_MAX];
2833
strcpy(tmpFileName, fileName);
2834
sprintf(fileName, "%s-%lu", tmpFileName,
2835
myGlobals.numHandledRequests[0]+myGlobals.numHandledRequests[1]);
2836
fd = fopen(fileName, "wb");
2840
fd = fopen(fileName, "wb");
2844
traceEvent(CONST_TRACE_WARNING, "Unable to create temp. file (%s). ", fileName);
2849
/* ****************************************************** */
2852
Function added in order to catch invalid
2853
strings passed on the command line.
2855
Thanks to Bailleux Christophe <cb@grolier.fr> for
2856
pointing out the finger at the problem.
2859
void stringSanityCheck(char* string) {
2862
if(string == NULL) {
2863
traceEvent(CONST_TRACE_FATALERROR, "Invalid string specified.");
2867
for(i=0, j=1; i<strlen(string); i++) {
2877
traceEvent(CONST_TRACE_FATALERROR, "Invalid string '%s' specified.",
2882
if((string[strlen(string)-1] == '/') ||
2883
(string[strlen(string)-1] == '\\')) {
2884
traceEvent(CONST_TRACE_WARNING, "Trailing slash removed from argument '%s'", string);
2885
string[strlen(string)-1] = '\0';
2889
/* ****************************************************** */
2892
Function added in order to catch invalid (too long)
2893
myGlobals.device names specified on the command line.
2895
Thanks to Bailleux Christophe <cb@grolier.fr> for
2896
pointing out the finger at the problem.
2899
void deviceSanityCheck(char* string) {
2902
if(strlen(string) > MAX_DEVICE_NAME_LEN)
2905
for(i=0, j=1; i<strlen(string); i++) {
2916
traceEvent(CONST_TRACE_FATALERROR, "Invalid device specified");
2921
/* ****************************************************** */
2923
#ifndef HAVE_SNPRINTF
2924
int snprintf(char *string, size_t maxlen, const char *format, ...) {
2928
va_start(args, format);
2929
vsprintf(string,format,args);
2935
/* ************************ */
2937
void fillDomainName(HostTraffic *el) {
2941
if(theDomainHasBeenComputed(el))
2944
accessAddrResMutex("fillDomainName");
2946
/* Reset values... */
2947
if(el->dnsDomainValue != NULL) free(el->dnsDomainValue);
2948
el->dnsDomainValue = NULL;
2949
if(el->dnsTLDValue != NULL) free(el->dnsTLDValue);
2950
el->dnsTLDValue = NULL;
2951
if(el->ip2ccValue != NULL) free(el->ip2ccValue);
2952
el->ip2ccValue = NULL;
2954
if((el->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_NAME) ||
2955
(el->hostResolvedName == NULL) ||
2956
(el->hostResolvedName[0] == '\0')) {
2957
/* Do NOT set FLAG_THE_DOMAIN_HAS_BEEN_COMPUTED - we still might learn the DNS Name later */
2958
releaseAddrResMutex();
2962
ip2cc = ip2CountryCode(el->hostIpAddress);
2964
if((ip2cc == NULL) || (strcmp(ip2cc, "***") == 0)) {
2965
/* We are unable to associate a domain with this IP address. */
2966
el->ip2ccValue = NULL;
2968
el->ip2ccValue = strdup(ip2cc);
2971
/* Walk back to the last . */
2972
i = strlen(el->hostResolvedName)-1;
2974
if(el->hostResolvedName[i] == '.')
2979
/* If we have it (.), use it, otherwise use the shortDomainName set at startup
2980
* last choice, leave it null from above
2983
el->dnsTLDValue = strdup(&el->hostResolvedName[i+1]);
2984
else if (myGlobals.shortDomainName != NULL) {
2985
/* Walk back to the last . */
2986
i = strlen(el->hostResolvedName)-1;
2988
if(myGlobals.shortDomainName[i] == '.')
2993
el->dnsTLDValue = strdup(&(myGlobals.shortDomainName[i+1]));
2997
/* Walk Forwards to the first . */
2998
for(i=0; i<strlen(el->hostResolvedName)-1; i++) {
2999
if(el->hostResolvedName[i] == '.')
3003
/* If we have it (.), use it, otherwise use the shortDomainName set at startup
3004
* last choice, leave it null from above
3006
if(i < strlen(el->hostResolvedName)-1)
3007
el->dnsDomainValue = strdup(&el->hostResolvedName[i+1]);
3008
else if (myGlobals.shortDomainName != NULL)
3009
el->dnsDomainValue = strdup(myGlobals.shortDomainName);
3011
FD_SET(FLAG_THE_DOMAIN_HAS_BEEN_COMPUTED, &el->flags);
3013
releaseAddrResMutex();
3017
/* ********************************* */
3019
/* similar to Java.String.trim() */
3020
void trimString(char* str) {
3021
int len = strlen(str), i, idx;
3022
char *out = (char *) malloc(sizeof(char) * (len+1));
3029
for(i=0, idx=0; i<len; i++)
3036
&& (out[idx-1] != ' ')
3037
&& (out[idx-1] != '\t'))
3038
out[idx++] = str[i];
3041
out[idx++] = str[i];
3047
strncpy(str, out, len);
3051
/* ****************************** */
3053
void setNBnodeNameType(HostTraffic *theHost, char nodeType,
3054
char isQuery, char* nbName) {
3057
if((nbName == NULL) || (strlen(nbName) == 0))
3060
if(strlen(nbName) >= (MAX_LEN_SYM_HOST_NAME-1)) /* (**) */
3061
nbName[MAX_LEN_SYM_HOST_NAME-2] = '\0';
3063
if(theHost->nonIPTraffic == NULL) theHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic));
3065
theHost->nonIPTraffic->nbNodeType = (char)nodeType;
3066
/* Courtesy of Roberto F. De Luca <deluca@tandar.cnea.gov.ar> */
3068
theHost->nonIPTraffic->nbNodeType = (char)nodeType;
3071
case 0x0: /* Workstation */
3072
case 0x20: /* Server/Messenger/Main name */
3074
if(theHost->nonIPTraffic->nbHostName == NULL) {
3075
theHost->nonIPTraffic->nbHostName = strdup(nbName);
3076
updateHostName(theHost);
3078
if(theHost->hostResolvedName[0] == '\0') {
3081
for(i=0; i<strlen(nbName); i++) if(isupper(nbName[i])) tolower(nbName[i]);
3082
setResolvedName(theHost, nbName, FLAG_HOST_SYM_ADDR_TYPE_NETBIOS);
3086
printf("DEBUG: nbHostName=%s [0x%X]\n", nbName, nodeType);
3091
case 0x1C: /* Domain Controller */
3092
case 0x1E: /* Domain */
3093
case 0x1B: /* Domain */
3094
case 0x1D: /* Workgroup (I think) */
3095
if(theHost->nonIPTraffic->nbDomainName == NULL) {
3096
if(strcmp(nbName, "__MSBROWSE__") && strncmp(&nbName[2], "__", 2)) {
3097
theHost->nonIPTraffic->nbDomainName = strdup(nbName);
3105
case 0x0: /* Workstation */
3106
FD_SET(FLAG_HOST_TYPE_WORKSTATION, &theHost->flags);
3107
case 0x20: /* Server */
3108
FD_SET(FLAG_HOST_TYPE_SERVER, &theHost->flags);
3109
case 0x1B: /* Master Browser */
3110
FD_SET(FLAG_HOST_TYPE_MASTER_BROWSER, &theHost->flags);
3115
/* ******************************************* */
3117
void addPassiveSessionInfo(HostAddr *theHost, u_short thePort) {
3119
time_t timeoutTime = myGlobals.actTime - PARM_PASSIVE_SESSION_MINIMUM_IDLE;
3122
traceEvent(CONST_TRACE_INFO, "DEBUG: Adding %ld:%d", theHost, thePort);
3125
for(i=0; i<passiveSessionsLen; i++) {
3126
if((passiveSessions[i].sessionPort == 0)
3127
|| (passiveSessions[i].creationTime < timeoutTime)) {
3128
addrcpy(&passiveSessions[i].sessionHost,theHost),
3129
passiveSessions[i].sessionPort = thePort,
3130
passiveSessions[i].creationTime = myGlobals.actTime;
3135
if(i == passiveSessionsLen) {
3136
/* Slot Not found */
3137
traceEvent(CONST_TRACE_INFO, "Info: passiveSessions[size=%d] is full", passiveSessionsLen);
3139
/* Shift table entries */
3140
for(i=1; i<passiveSessionsLen; i++) {
3141
passiveSessions[i-1].sessionHost = passiveSessions[i].sessionHost,
3142
passiveSessions[i-1].sessionPort = passiveSessions[i].sessionPort;
3144
addrcpy(&passiveSessions[passiveSessionsLen-1].sessionHost,theHost),
3145
passiveSessions[passiveSessionsLen-1].sessionPort = thePort;
3149
/* ******************************************* */
3151
int isPassiveSession(HostAddr *theHost, u_short thePort) {
3155
traceEvent(CONST_TRACE_INFO, "DEBUG: Searching for %ld:%d",
3159
for(i=0; i<passiveSessionsLen; i++) {
3160
if((addrcmp(&passiveSessions[i].sessionHost,theHost) == 0)
3161
&& (passiveSessions[i].sessionPort == thePort)) {
3162
addrinit(&passiveSessions[i].sessionHost),
3163
passiveSessions[i].sessionPort = 0,
3164
passiveSessions[i].creationTime = 0;
3166
traceEvent(CONST_TRACE_INFO, "DEBUG: Found passive FTP session");
3175
/* ******************************************* */
3177
void initPassiveSessions(void) {
3180
len = sizeof(SessionInfo)*MAX_PASSIVE_FTP_SESSION_TRACKER;
3181
passiveSessions = (SessionInfo*)malloc(len);
3182
memset(passiveSessions, 0, len);
3183
passiveSessionsLen = MAX_PASSIVE_FTP_SESSION_TRACKER;
3186
/* ******************************* */
3188
void termPassiveSessions(void) {
3189
if(myGlobals.enableSessionHandling)
3190
free(passiveSessions);
3193
/* ******************************* */
3195
int getPortByName(ServiceEntry **theSvc, char* portName) {
3198
for(idx=0; idx<myGlobals.numActServices; idx++) {
3201
if(theSvc[idx] != NULL)
3202
traceEvent(CONST_TRACE_INFO, "DEBUG: %d/%s [%s]",
3204
theSvc[idx]->name, portName);
3207
if((theSvc[idx] != NULL)
3208
&& (strcmp(theSvc[idx]->name, portName) == 0))
3209
return(theSvc[idx]->port);
3215
/* ******************************* */
3217
char* getPortByNumber(ServiceEntry **theSvc, int port) {
3218
int idx = port % myGlobals.numActServices;
3224
if((scan != NULL) && (scan->port == port))
3226
else if(scan == NULL)
3229
idx = (idx+1) % myGlobals.numActServices;
3233
/* ******************************* */
3235
char* getPortByNum(int port, int type) {
3238
if(type == IPPROTO_TCP) {
3239
rsp = getPortByNumber(myGlobals.tcpSvc, port);
3241
rsp = getPortByNumber(myGlobals.udpSvc, port);
3247
/* ******************************* */
3249
char* getAllPortByNum(int port, char *outBuf, int outBufLen) {
3252
rsp = getPortByNumber(myGlobals.tcpSvc, port); /* Try TCP first... */
3254
rsp = getPortByNumber(myGlobals.udpSvc, port); /* ...then UDP */
3259
if(snprintf(outBuf, outBufLen, "%d", port) < 0)
3265
/* ******************************* */
3267
int getAllPortByName(char* portName) {
3270
rsp = getPortByName(myGlobals.tcpSvc, portName); /* Try TCP first... */
3272
rsp = getPortByName(myGlobals.udpSvc, portName); /* ...then UDP */
3278
/* ******************************* */
3280
void addPortHashEntry(ServiceEntry **theSvc, int port, char* name) {
3281
int idx = port % myGlobals.numActServices;
3288
theSvc[idx] = (ServiceEntry*)malloc(sizeof(ServiceEntry));
3289
theSvc[idx]->port = (u_short)port;
3290
theSvc[idx]->name = strdup(name);
3292
} else if(scan->port == port) {
3293
break; /* Already there */
3295
idx = (idx+1) % myGlobals.numActServices;
3299
/* ******************************* */
3301
void resetUsageCounter(UsageCounter *counter) {
3304
memset(counter, 0, sizeof(UsageCounter));
3306
for(i=0; i<MAX_NUM_CONTACTED_PEERS; i++)
3307
setEmptySerial(&counter->peersSerials[i]);
3310
/* ************************************ */
3313
This function has to be used to reset (i.e. initialize to
3314
empty values in the correct range) HostTraffic
3318
void resetSecurityHostTraffic(HostTraffic *el) {
3320
if(el->secHostPkts == NULL) return;
3322
resetUsageCounter(&el->secHostPkts->synPktsSent);
3323
resetUsageCounter(&el->secHostPkts->rstPktsSent);
3324
resetUsageCounter(&el->secHostPkts->rstAckPktsSent);
3325
resetUsageCounter(&el->secHostPkts->synFinPktsSent);
3326
resetUsageCounter(&el->secHostPkts->finPushUrgPktsSent);
3327
resetUsageCounter(&el->secHostPkts->nullPktsSent);
3328
resetUsageCounter(&el->secHostPkts->ackXmasFinSynNullScanSent);
3329
resetUsageCounter(&el->secHostPkts->rejectedTCPConnSent);
3330
resetUsageCounter(&el->secHostPkts->establishedTCPConnSent);
3331
resetUsageCounter(&el->secHostPkts->terminatedTCPConnServer);
3332
resetUsageCounter(&el->secHostPkts->terminatedTCPConnClient);
3333
resetUsageCounter(&el->secHostPkts->udpToClosedPortSent);
3334
resetUsageCounter(&el->secHostPkts->udpToDiagnosticPortSent);
3335
resetUsageCounter(&el->secHostPkts->tcpToDiagnosticPortSent);
3336
resetUsageCounter(&el->secHostPkts->tinyFragmentSent);
3337
resetUsageCounter(&el->secHostPkts->icmpFragmentSent);
3338
resetUsageCounter(&el->secHostPkts->overlappingFragmentSent);
3339
resetUsageCounter(&el->secHostPkts->closedEmptyTCPConnSent);
3340
resetUsageCounter(&el->secHostPkts->icmpPortUnreachSent);
3341
resetUsageCounter(&el->secHostPkts->icmpHostNetUnreachSent);
3342
resetUsageCounter(&el->secHostPkts->icmpProtocolUnreachSent);
3343
resetUsageCounter(&el->secHostPkts->icmpAdminProhibitedSent);
3344
resetUsageCounter(&el->secHostPkts->malformedPktsSent);
3348
resetUsageCounter(&el->contactedRcvdPeers);
3350
resetUsageCounter(&el->secHostPkts->synPktsRcvd);
3351
resetUsageCounter(&el->secHostPkts->rstPktsRcvd);
3352
resetUsageCounter(&el->secHostPkts->rstAckPktsRcvd);
3353
resetUsageCounter(&el->secHostPkts->synFinPktsRcvd);
3354
resetUsageCounter(&el->secHostPkts->finPushUrgPktsRcvd);
3355
resetUsageCounter(&el->secHostPkts->nullPktsRcvd);
3356
resetUsageCounter(&el->secHostPkts->ackXmasFinSynNullScanRcvd);
3357
resetUsageCounter(&el->secHostPkts->rejectedTCPConnRcvd);
3358
resetUsageCounter(&el->secHostPkts->establishedTCPConnRcvd);
3359
resetUsageCounter(&el->secHostPkts->udpToClosedPortRcvd);
3360
resetUsageCounter(&el->secHostPkts->udpToDiagnosticPortRcvd);
3361
resetUsageCounter(&el->secHostPkts->tcpToDiagnosticPortRcvd);
3362
resetUsageCounter(&el->secHostPkts->tinyFragmentRcvd);
3363
resetUsageCounter(&el->secHostPkts->icmpFragmentRcvd);
3364
resetUsageCounter(&el->secHostPkts->overlappingFragmentRcvd);
3365
resetUsageCounter(&el->secHostPkts->closedEmptyTCPConnRcvd);
3366
resetUsageCounter(&el->secHostPkts->icmpPortUnreachRcvd);
3367
resetUsageCounter(&el->secHostPkts->icmpHostNetUnreachRcvd);
3368
resetUsageCounter(&el->secHostPkts->icmpProtocolUnreachRcvd);
3369
resetUsageCounter(&el->secHostPkts->icmpAdminProhibitedRcvd);
3370
resetUsageCounter(&el->secHostPkts->malformedPktsRcvd);
3372
resetUsageCounter(&el->contactedSentPeers);
3373
resetUsageCounter(&el->contactedRcvdPeers);
3374
resetUsageCounter(&el->contactedRouters);
3377
/* ********************************************* */
3379
char* mapIcmpType(int icmpType) {
3380
static char icmpString[4];
3382
icmpType %= ICMP_MAXTYPE; /* Just to be safe... */
3385
case 0: return("ECHOREPLY");
3386
case 3: return("UNREACH");
3387
case 4: return("SOURCEQUENCH");
3388
case 5: return("REDIRECT");
3389
case 8: return("ECHO");
3390
case 9: return("ROUTERADVERT");
3391
case 10: return("ROUTERSOLICI");
3392
case 11: return("TIMXCEED");
3393
case 12: return("PARAMPROB");
3394
case 13: return("TIMESTAMP");
3395
case 14: return("TIMESTAMPREPLY");
3396
case 15: return("INFOREQ");
3397
case 16: return("INFOREQREPLY");
3398
case 17: return("MASKREQ");
3399
case 18: return("MASKREPLY");
3401
sprintf(icmpString, "%d", icmpType);
3406
/* ************************************ */
3408
/* Do not delete this line! */
3409
#undef incrementUsageCounter
3411
int _incrementUsageCounter(UsageCounter *counter,
3412
HostTraffic *theHost, int actualDeviceId,
3413
char* file, int line) {
3417
traceEvent(CONST_TRACE_INFO, "DEBUG: incrementUsageCounter(%u) @ %s:%d",
3418
peerIdx, file, line);
3421
if(theHost == NULL) return(0);
3423
counter->value.value++;
3425
for(i=0; i<MAX_NUM_CONTACTED_PEERS; i++) {
3426
if(emptySerial(&counter->peersSerials[i])) {
3427
copySerial(&counter->peersSerials[i], &theHost->hostSerial);
3430
} else if(cmpSerial(&counter->peersSerials[i], &theHost->hostSerial)) {
3437
for(i=0; i<MAX_NUM_CONTACTED_PEERS-1; i++)
3438
copySerial(&counter->peersSerials[i], &counter->peersSerials[i+1]);
3440
/* Add host serial and not it's index */
3441
copySerial(&counter->peersSerials[MAX_NUM_CONTACTED_PEERS-1], &theHost->hostSerial);
3442
return(1); /* New entry added */
3448
/* ******************************** */
3450
int fetchPrefsValue(char *key, char *value, int valueLen) {
3454
if((value == NULL) || (myGlobals.capturePackets == FLAG_NTOPSTATE_TERM)) return(-1);
3457
traceEvent(CONST_TRACE_INFO, "DEBUG: Entering fetchPrefValue()");
3461
key_data.dptr = key;
3462
key_data.dsize = strlen(key_data.dptr);
3464
if(myGlobals.prefsFile == NULL) {
3466
traceEvent(CONST_TRACE_INFO, "DEBUG: Leaving fetchPrefValue()");
3468
return(-1); /* ntop is quitting... */
3471
data_data = gdbm_fetch(myGlobals.prefsFile, key_data);
3473
memset(value, 0, valueLen);
3475
if(data_data.dptr != NULL) {
3476
int len = min(valueLen,data_data.dsize);
3477
strncpy(value, data_data.dptr, len);
3479
free(data_data.dptr);
3480
/* traceEvent(CONST_TRACE_INFO, "Read %s=%s.", key, value); */
3486
/* ******************************** */
3488
void storePrefsValue(char *key, char *value) {
3492
if((value == NULL) || (myGlobals.capturePackets == FLAG_NTOPSTATE_TERM)) return;
3495
traceEvent(CONST_TRACE_INFO, "DEBUG:DEBUG: Entering storePrefsValue()");
3498
memset(&key_data, 0, sizeof(key_data));
3499
key_data.dptr = key;
3500
key_data.dsize = strlen(key_data.dptr);
3502
memset(&data_data, 0, sizeof(data_data));
3503
data_data.dptr = value;
3504
data_data.dsize = strlen(value);
3506
if(myGlobals.prefsFile == NULL) {
3508
traceEvent(CONST_TRACE_INFO, "DEBUG: Leaving storePrefsValue()");
3510
; /* ntop is quitting... */
3513
if(gdbm_store(myGlobals.prefsFile, key_data, data_data, GDBM_REPLACE) != 0)
3514
traceEvent(CONST_TRACE_ERROR, "While adding %s=%s.", key, value);
3516
/* traceEvent(CONST_TRACE_INFO, "Storing %s=%s.", key, value); */
3520
/* ******************************** */
3522
#ifndef HAVE_LOCALTIME_R
3525
#ifdef CFG_MULTITHREADED
3526
static PthreadMutex localtimeMutex;
3527
static char localtimeMutexInitialized = 0;
3530
struct tm *localtime_r(const time_t *t, struct tm *tp) {
3533
#if defined(CFG_MULTITHREADED)
3534
if(!localtimeMutexInitialized) {
3535
createMutex(&localtimeMutex);
3536
localtimeMutexInitialized = 1;
3538
accessMutex(&localtimeMutex, "localtime_r");
3541
theTime = localtime(t);
3544
memcpy(tp, theTime, sizeof(struct tm));
3546
memset(tp, 0, sizeof(struct tm)); /* What shall I do ? */
3548
#if defined(CFG_MULTITHREADED)
3549
releaseMutex(&localtimeMutex);
3556
/* ************************************ */
3558
int guessHops(HostTraffic *el) {
3561
if(subnetPseudoLocalHost(el) || (el->minTTL == 0)) numHops = 0;
3562
else if(el->minTTL <= 8) numHops = el->minTTL-1;
3563
else if(el->minTTL <= 32) numHops = 32 - el->minTTL;
3564
else if(el->minTTL <= 64) numHops = 64 - el->minTTL;
3565
else if(el->minTTL <= 128) numHops = 128 - el->minTTL;
3566
else if(el->minTTL <= 256) numHops = 255 - el->minTTL;
3571
/* ************************************ */
3576
unsigned int ntop_sleep(unsigned int secs) {
3577
unsigned int unsleptTime = secs, rest;
3579
while((rest = sleep(unsleptTime)) > 0)
3586
/* *************************************** */
3588
void unescape(char *dest, int destLen, char *url) {
3595
memset(dest, 0, destLen);
3596
for (i = 0; i < len && at < destLen; i++) {
3597
if (url[i] == '%' && i+2 < len) {
3602
sscanf(hex, "%02x", &val);
3605
dest[at++] = val & 0xFF;
3606
} else if(url[i] == '+') {
3609
dest[at++] = url[i];
3613
/* ******************************** */
3615
void incrementTrafficCounter(TrafficCounter *ctr, Counter value) {
3616
ctr->value += value, ctr->modified = 1;
3619
/* ******************************** */
3621
void resetTrafficCounter(TrafficCounter *ctr) {
3622
ctr->value = 0, ctr->modified = 0;
3625
/* ******************************** */
3627
void allocateElementHash(int deviceId, u_short hashType) {
3628
int fcmemLen = sizeof(FcFabricElementHash*)*MAX_ELEMENT_HASH;
3632
if(myGlobals.device[deviceId].vsanHash == NULL) {
3633
myGlobals.device[deviceId].vsanHash = (FcFabricElementHash**)malloc(fcmemLen);
3634
memset(myGlobals.device[deviceId].vsanHash, 0, fcmemLen);
3640
/* *************************************************** */
3642
u_int numActiveSenders(u_int deviceId) {
3643
u_int numSenders = 0;
3646
for(el=getFirstHost(deviceId);
3647
el != NULL; el = getNextHost(deviceId, el)) {
3648
if(broadcastHost(el) || (el->pktSent.value == 0))
3650
else if (isFcHost (el) && (el->hostFcAddress.domain == FC_ID_SYSTEM_DOMAIN))
3659
/* *************************************************** */
3660
u_int numActiveVsans(u_int deviceId)
3662
u_int numVsans = 0, i;
3663
FcFabricElementHash **theHash;
3665
if ((theHash = myGlobals.device[deviceId].vsanHash) == NULL) {
3669
for (i=0; i<MAX_ELEMENT_HASH; i++) {
3670
if((theHash[i] != NULL) && (theHash[i]->vsanId < MAX_HASHDUMP_ENTRY) &&
3671
(theHash[i]->vsanId < MAX_USER_VSAN)) {
3672
if (theHash[i]->totBytes.value)
3682
/* *************************************************** */
3684
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
3686
u_int32_t xaton(char *s) {
3687
u_int32_t a, b, c, d;
3689
if(4!=sscanf(s, "%d.%d.%d.%d", &a, &b, &c, &d))
3691
return((a&0xFF)<<24)|((b&0xFF)<<16)|((c&0xFF)<<8)|(d&0xFF);
3694
/* ******************************************************************* */
3696
void addNodeInternal(u_int32_t ip, int prefix, char *country, int as) {
3697
IPNode *p1 = NULL, *p2 = NULL;
3701
p1 = myGlobals.countryFlagHead;
3703
p1 = myGlobals.asHead;
3705
for(i=0; i<prefix; i++) {
3706
b=(ip>>(31-i)) & 0x1;
3708
if(!(p2=malloc(sizeof(IPNode))))
3710
memset(p2, 0, sizeof(IPNode));
3713
myGlobals.ipCountryMem += sizeof(IPNode);
3715
myGlobals.asMem += sizeof(IPNode);
3724
if(country != NULL) {
3725
if(p2->node.cc[0] == 0)
3726
strncpy(p2->node.cc, country, sizeof(p2->node.cc));
3728
if(p2->node.as == 0)
3733
/* ******************************************************************* */
3735
char *ip2CountryCode(HostAddr ip) {
3736
IPNode *p = myGlobals.countryFlagHead;
3741
if (ip.hostFamily == AF_INET6)
3743
addr = ip.Ip4Address.s_addr;
3746
if(p->node.cc[0] != 0)
3748
b = (addr >>(31-i)) & 0x1;
3756
/* ******************************************************** */
3758
#ifdef PARM_SHOW_NTOP_HEARTBEAT
3759
void _HEARTBEAT(int beatLevel, char* file, int line, char * format, ...) {
3760
char buf[LEN_GENERAL_WORK_BUFFER];
3763
myGlobals.heartbeatCounter++;
3765
if((format != NULL) && (PARM_SHOW_NTOP_HEARTBEAT >= beatLevel) ) {
3766
memset(buf, 0, LEN_GENERAL_WORK_BUFFER);
3767
va_start(va_ap, format);
3768
vsnprintf(buf, LEN_GENERAL_WORK_BUFFER-1, format, va_ap);
3771
traceEvent(CONST_TRACE_INFO, "HEARTBEAT(%09u)[%s:%d]: %s", myGlobals.heartbeatCounter, file, line, buf);
3776
#ifdef MAKE_WITH_I18N
3777
char *i18n_xvert_locale2common(const char *input) {
3779
* locales are ll[_XX][.char][@modifier]
3781
* Fix it up to our common format(ll_XX), stripped of char and modifier.
3783
* NB: We picked this common format because it's usable in a directory
3784
* (html_ll_XX) where the Accept-Language version(ll-XX) wouldn't always be.
3787
char *output, *work;
3789
output = strdup(input);
3791
work = strchr(output, '.');
3795
work = strchr(output, '@');
3802
char *i18n_xvert_acceptlanguage2common(const char *input) {
3804
* Accept-Language: headers are ll[-XX] or ll-*
3806
* Fix it up to our common format(ll_XX), with the - swapped for a _
3808
* NB: We picked this common format because it's usable in a directory
3809
* (html_ll_XX) where the Accept-Language version(ll-XX) wouldn't always be.
3812
char *output, *work;
3814
output = strdup(input);
3816
work = strchr(output, '*');
3818
/* Backup to erase the - of the -* combo */
3822
work = strchr(output, '-');
3826
work = strchr(output, '_');
3828
while(work[0] != '\0') {
3829
work[0] = toupper(work[0]);
3835
#endif /* MAKE_WITH_I18N */
3837
/* *************************************** */
3839
void setHostFingerprint(HostTraffic *srcHost) {
3841
char *WIN, *MSS, *WSS, *ttl, *flags, *work;
3842
int S, N, D, T, done = 0;
3843
char fingerprint[32];
3845
u_char compressedFormat;
3847
#ifdef FINGERPRINT_DEBUG
3848
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint(0x%08x)", srcHost);
3851
if(srcHost->fingerprint == NULL) {
3852
/* No fingerprint yet */
3853
#ifdef FINGERPRINT_DEBUG
3854
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 1");
3859
#ifdef FINGERPRINT_DEBUG
3860
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() '%s'(%d)",
3861
srcHost->fingerprint, strlen(srcHost->fingerprint));
3864
if(srcHost->fingerprint[0] == ':') {
3865
/* OS already calculated */
3866
#ifdef FINGERPRINT_DEBUG
3867
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 2");
3871
if(strlen(srcHost->fingerprint) < 28) {
3872
#ifdef FINGERPRINT_DEBUG
3873
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 3");
3878
if(myGlobals.childntoppid != 0) {
3879
#ifdef FINGERPRINT_DEBUG
3880
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 4");
3882
return; /* Reporting fork()ed child, don't update! */
3885
accessAddrResMutex("setHostFingerprint");
3887
if(snprintf(fingerprint, sizeof(fingerprint)-1, "%s", srcHost->fingerprint) < 0)
3890
WIN = strtok_r(fingerprint, ":", &strtokState); if(!WIN) goto unknownFingerprint;
3891
MSS = strtok_r(NULL, ":", &strtokState); if(!MSS) goto unknownFingerprint;
3892
ttl = strtok_r(NULL, ":", &strtokState); if(!ttl) goto unknownFingerprint;
3893
WSS = strtok_r(NULL, ":", &strtokState); if(!WSS) goto unknownFingerprint;
3894
work = strtok_r(NULL, ":", &strtokState); if(!work) goto unknownFingerprint;
3896
work = strtok_r(NULL, ":", &strtokState); if(!work) goto unknownFingerprint;
3898
work = strtok_r(NULL, ":", &strtokState); if(!work) goto unknownFingerprint;
3900
work = strtok_r(NULL, ":", &strtokState); if(!work) goto unknownFingerprint;
3902
flags = strtok_r(NULL, ":", &strtokState); if(!flags) goto unknownFingerprint;
3904
#ifdef FINGERPRINT_DEBUG
3905
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: WIN%s MSS%s ttl%s WSS%s S%d N%d D%d T%s FLAGS%s",
3906
WIN, MSS, ttl, WSS, S, N, D, T, flags);
3909
fd=checkForInputFile(NULL, NULL, CONST_OSFINGERPRINT_FILE, NULL, &compressedFormat);
3915
while(readInputFile(fd, NULL, FALSE, compressedFormat, 0,
3916
line, sizeof(line), &numLoaded) == 0) {
3918
if((line[0] == '\0') || (line[0] == '#') || (strlen(line) < 30)) continue;
3919
line[strlen(line)-1] = '\0';
3922
ptr = strtok_r(line, ":", &strtokState); if(ptr == NULL) continue;
3923
if(strcmp(ptr, WIN)) continue;
3924
b = strtok_r(NULL, ":", &strtokState); if(b == NULL) continue;
3925
if(strcmp(MSS, "_MSS") != 0) {
3926
if(strcmp(b, "_MSS") != 0) {
3927
if(strcmp(b, MSS)) continue;
3931
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3932
if(strcmp(ptr, ttl)) continue;
3934
d = strtok_r(NULL, ":", &strtokState); if(d == NULL) continue;
3935
if(strcmp(WSS, "WS") != 0) {
3936
if(strcmp(d, "WS") != 0) {
3937
if(strcmp(d, WSS)) continue;
3941
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3942
if(atoi(ptr) != S) continue;
3943
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3944
if(atoi(ptr) != N) continue;
3945
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3946
if(atoi(ptr) != D) continue;
3947
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3948
if(atoi(ptr) != T) continue;
3949
ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
3950
if(strcmp(ptr, flags)) continue;
3953
strlen(srcHost->fingerprint) is 29 as the fingerprint length is so
3954
Example: 0212:_MSS:80:WS:0:1:0:0:A:LT
3957
if(srcHost->fingerprint) free(srcHost->fingerprint);
3958
srcHost->fingerprint = strdup(&line[28]);
3962
readInputFile(fd, NULL, TRUE, compressedFormat, 0, NULL, 0, &numLoaded);
3968
#ifdef FINGERPRINT_DEBUG
3970
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: Unable to open file");
3975
/* Unknown fingerprint */
3976
unknownFingerprint: /* Empty OS name */
3977
srcHost->fingerprint[0] = ':', srcHost->fingerprint[1] = '\0';
3979
#ifdef FINGERPRINT_DEBUG
3981
traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: match! %s", srcHost->fingerprint);
3984
releaseAddrResMutex();
3987
/* ************************************************ */
3989
#ifndef MEMORY_DEBUG
3990
#undef gdbm_firstkey
3997
int ntop_gdbm_delete(GDBM_FILE g, datum d) {
4000
#ifdef CFG_MULTITHREADED
4001
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4002
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_delete");
4005
rc = gdbm_delete(g, d);
4007
#ifdef CFG_MULTITHREADED
4008
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4009
releaseMutex(&myGlobals.gdbmMutex);
4015
/* ****************************************** */
4017
datum ntop_gdbm_firstkey(GDBM_FILE g) {
4020
memset(&theData, 0, sizeof(theData));
4022
#ifdef CFG_MULTITHREADED
4023
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4024
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_firstkey");
4027
theData = gdbm_firstkey(g);
4029
#ifdef CFG_MULTITHREADED
4030
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4031
releaseMutex(&myGlobals.gdbmMutex);
4037
/* ****************************************** */
4039
void ntop_gdbm_close(GDBM_FILE g) {
4040
#ifdef CFG_MULTITHREADED
4041
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4042
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_close");
4047
#ifdef CFG_MULTITHREADED
4048
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4049
releaseMutex(&myGlobals.gdbmMutex);
4053
/* ******************************************* */
4055
datum ntop_gdbm_nextkey(GDBM_FILE g, datum d) {
4058
memset(&theData, 0, sizeof(theData));
4060
#ifdef CFG_MULTITHREADED
4061
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4062
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_nextkey");
4065
theData = gdbm_nextkey(g, d);
4067
#ifdef CFG_MULTITHREADED
4068
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4069
releaseMutex(&myGlobals.gdbmMutex);
4075
/* ******************************************* */
4077
datum ntop_gdbm_fetch(GDBM_FILE g, datum d) {
4080
memset(&theData, 0, sizeof(theData));
4082
#ifdef CFG_MULTITHREADED
4083
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4084
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_fetch");
4087
theData = gdbm_fetch(g, d);
4089
#ifdef CFG_MULTITHREADED
4090
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4091
releaseMutex(&myGlobals.gdbmMutex);
4097
/* ******************************************* */
4099
int ntop_gdbm_store(GDBM_FILE g, datum d, datum v, int r) {
4102
#ifdef CFG_MULTITHREADED
4103
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4104
accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_store");
4107
rc = gdbm_store(g, d, v, r);
4109
#ifdef CFG_MULTITHREADED
4110
if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
4111
releaseMutex(&myGlobals.gdbmMutex);
4116
#endif /* MEMORY_DEBUG */
4118
/* ******************************************* */
4120
void handleWhiteBlackListAddresses(char* addresses,
4121
u_int32_t theNetworks[MAX_NUM_NETWORKS][3],
4124
int outAddressesLen) {
4127
if((addresses == NULL) ||(strlen(addresses) == 0) ) {
4128
/* No list - return with numNets = 0 */
4129
outAddresses[0]='\0';
4133
handleAddressLists(addresses, theNetworks,
4134
numNets, outAddresses,
4136
CONST_HANDLEADDRESSLISTS_NETFLOW);
4139
/* ****************************** */
4141
/* This function checks if a host is OK to save
4142
* i.e. specified in the white list and NOT specified in the blacklist
4144
* We return 1 or 2 - DO NOT SAVE
4145
* (1 means failed white list,
4146
* 2 means matched black list)
4149
* We use the routines from util.c ...
4150
* For them, 1=PseudoLocal, which means it's in the set
4151
* So we have to flip the whitelist code
4153
unsigned short isOKtoSave(u_int32_t addr,
4154
u_int32_t whiteNetworks[MAX_NUM_NETWORKS][3],
4155
u_int32_t blackNetworks[MAX_NUM_NETWORKS][3],
4156
u_short numWhiteNets, u_short numBlackNets) {
4158
struct in_addr workAddr;
4160
workAddr.s_addr = addr;
4162
if(numBlackNets > 0) {
4163
rc = __pseudoLocalAddress(&workAddr, blackNetworks, numBlackNets);
4168
if(numWhiteNets > 0) {
4169
rc = __pseudoLocalAddress(&workAddr, whiteNetworks, numWhiteNets);
4173
return(0 /* SAVE */);
4176
#ifndef HAVE_PCAP_OPEN_DEAD
4188
struct pcap_stat stat;
4190
int use_bpf; /* using kernel filter */
4191
u_long TotPkts; /* can't oflow for 79 hrs on ether */
4192
u_long TotAccepted; /* count accepted by filter */
4193
u_long TotDrops; /* count of dropped packets */
4194
long TotMissed; /* missed by i/f during this run */
4195
long OrigMissed; /* missed by i/f before this run */
4197
int sock_packet; /* using Linux 2.0 compatible interface */
4198
int timeout; /* timeout specified to pcap_open_live */
4199
int clear_promisc; /* must clear promiscuous mode when we close */
4200
int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
4201
int lo_ifindex; /* interface index of the loopback device */
4202
char *device; /* device name */
4203
struct pcap *next; /* list of open promiscuous sock_packet pcaps */
4211
int tzoff; /* timezone offset */
4212
int offset; /* offset for proper alignment */
4226
* Place holder for pcap_next().
4232
* Placeholder for filter code if bpf not in kernel.
4234
struct bpf_program fcode;
4236
char errbuf[PCAP_ERRBUF_SIZE];
4239
pcap_t *pcap_open_dead(int linktype, int snaplen)
4243
p = malloc(sizeof(*p));
4246
memset (p, 0, sizeof(*p));
4248
p->snapshot = snaplen;
4249
p->linktype = linktype;
4254
/* ******************************** */
4256
int setSpecifiedUser(void) {
4259
* set user to be as inoffensive as possible
4261
/* user id specified on commandline */
4262
if((setgid(myGlobals.groupId) != 0) || (setuid(myGlobals.userId) != 0)) {
4263
traceEvent(CONST_TRACE_FATALERROR, "Unable to change user ID");
4266
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "Now running as requested user '%s' (%d:%d)",
4267
myGlobals.effectiveUserName, myGlobals.userId, myGlobals.groupId);
4269
if((myGlobals.userId != 0) || (myGlobals.groupId != 0)) {
4270
#if defined(DARWIN) || defined(FREEBSD)
4274
This is dead code but it's necessary under OSX. In fact the linker
4275
notices that the RRD stuff is not used in the main code so it is
4276
ignored. At runtime when the RRD plugin comes up, the dynamic linker
4277
failes because the rrd_* are not found.
4280
p = (unsigned long)rrd_fetch;
4281
p += (unsigned long)rrd_graph;
4282
p += (unsigned long)rrd_create;
4283
p += (unsigned long)rrd_last;
4284
p += (unsigned long)rrd_update;
4285
p += (unsigned long)rrd_test_error;
4286
p += (unsigned long)rrd_get_error;
4287
p += (unsigned long)rrd_clear_error;
4299
/* ******************************************************************* */
4301
u_short ip2AS(HostAddr ip) {
4307
if (ip.hostFamily == AF_INET6)
4310
addr = ip.Ip4Address.s_addr;
4312
p = myGlobals.asHead;
4318
b=(addr>>(31-i)) & 0x1;
4328
traceEvent(CONST_TRACE_INFO, "%s: %d AS", _intoa(&addr, buf, sizeof(buf)), as);
4335
/* ************************************ */
4337
u_int16_t getHostAS(HostTraffic *el) {
4338
return(el->hostAS || (el->hostAS = ip2AS(el->hostIpAddress)));
4341
/* ************************************ */
4343
int emptySerial(HostSerial *a) {
4344
return(a->serialType == 0);
4347
/* ********************************** */
4349
int cmpSerial(HostSerial *a, HostSerial *b) {
4350
return(!memcmp(a, b, sizeof(HostSerial)));
4353
/* ********************************** */
4355
int copySerial(HostSerial *a, HostSerial *b) {
4356
return(!memcpy(a, b, sizeof(HostSerial)));
4359
/* ********************************** */
4361
void setEmptySerial(HostSerial *a) {
4362
memset(a, 0, sizeof(HostSerial));
4365
/* ********************************* */
4367
void addPortToList(HostTraffic *host, int *thePorts /* 0...MAX_NUM_RECENT_PORTS */, u_short port) {
4371
FD_SET(FLAG_HOST_IP_ZERO_PORT_TRAFFIC, &host->flags);
4373
for(i = 0, found = 0; i<MAX_NUM_RECENT_PORTS; i++)
4374
if(thePorts[i] == port) {
4380
for(i = 0; i<(MAX_NUM_RECENT_PORTS-1); i++)
4381
thePorts[i] = thePorts[i+1];
4383
thePorts[MAX_NUM_RECENT_PORTS-1] = port;
4387
/* ************************************ */
4391
void saveNtopPid(void) {
4392
char pidFileName[NAME_MAX];
4395
myGlobals.basentoppid = getpid();
4396
sprintf(pidFileName, "%s/%s",
4398
/* We're not root */ myGlobals.dbPath :
4399
/* We are root */ DEFAULT_NTOP_PID_DIRECTORY,
4400
DEFAULT_NTOP_PIDFILE);
4401
fd = fopen(pidFileName, "wb");
4404
traceEvent(CONST_TRACE_WARNING, "INIT: Unable to create pid file (%s)", pidFileName);
4406
fprintf(fd, "%d\n", myGlobals.basentoppid);
4408
traceEvent(CONST_TRACE_INFO, "INIT: Created pid file (%s)", pidFileName);
4412
/* ********************************** */
4414
void removeNtopPid(void) {
4415
char pidFileName[NAME_MAX];
4418
sprintf(pidFileName, "%s/%s",
4420
/* We're not root */ myGlobals.dbPath :
4421
/* We are root */ DEFAULT_NTOP_PID_DIRECTORY,
4422
DEFAULT_NTOP_PIDFILE);
4423
rc = unlink(pidFileName);
4425
traceEvent(CONST_TRACE_INFO, "TERM: Removed pid file (%s)", pidFileName);
4427
traceEvent(CONST_TRACE_WARNING, "TERM: Unable to remove pid file (%s)", pidFileName);
4433
/* ************************************ */
4435
/* The following two routines have been extracted from Ethereal */
4437
bytestring_to_str(const u_int8_t *ad, u_int32_t len, char punct) {
4438
static char str[3][32];
4443
/* At least one version of Apple's C compiler/linker is buggy, causing
4444
a complaint from the linker about the "literal C string section"
4445
not ending with '\0' if we initialize a 16-element "char" array with
4446
a 16-character string, the fact that initializing such an array with
4447
such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
4448
'\0' byte in the string nonwithstanding. */
4449
static const char hex_digits[16] =
4450
{ '0', '1', '2', '3', '4', '5', '6', '7',
4451
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
4459
if (cur == &str[0][0]) {
4461
} else if (cur == &str[1][0]) {
4471
*--p = hex_digits[octet&0xF];
4473
*--p = hex_digits[octet&0xF];
4484
fc_to_str(const u_int8_t *ad)
4486
return bytestring_to_str (ad, 3, '.');
4490
fcwwn_to_str (const u_int8_t *ad)
4492
u_int8_t zero_wwn[LEN_WWN_ADDRESS] = {0,0,0,0,0,0,0,0};
4494
if (!memcmp (ad, zero_wwn, LEN_WWN_ADDRESS)) {
4498
return bytestring_to_str (ad, 8, ':');
4501
/* ************************************ */
4503
#if defined(CFG_MULTITHREADED) && defined(MAKE_WITH_SCHED_YIELD)
4507
/* BStrauss - August 2003 - Check the flag and skip the call... */
4508
extern int ntop_sched_yield(char *file, int line) {
4511
static int firstTime=0;
4514
traceEvent(CONST_TRACE_INFO, "DEBUG: firstTime in ntop_sched_yield()");
4519
if(!myGlobals.disableSchedYield) {
4523
traceEvent(CONST_TRACE_INFO, "DEBUG: skipping sched_yield()");
4531
extern char *crypt (__const char *__key, __const char *__salt) {
4536
/* ********************************* */
4541
inet_ntop4(src, dst, size)
4546
static const char fmt[] = "%u.%u.%u.%u";
4547
char tmp[sizeof "255.255.255.255"];
4550
nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
4552
return (NULL); /* we assume "errno" was set by "snprintf()" */
4553
if ((size_t)nprinted > size) {
4561
#define NS_IN6ADDRSZ 16
4563
static const char *inet_ntop6(const u_char *src, char *dst, size_t size) {
4565
* Note that int32_t and int16_t need only be "at least" large enough
4566
* to contain a value of the specified size. On some systems, like
4567
* Crays, there is no such thing as an integer variable with 16 bits.
4568
* Keep this in mind if you think this function should have been coded
4569
* to use pointer overlays. All the world's not a VAX.
4571
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
4572
struct { int base, len; } best, cur;
4573
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
4578
* Copy the input (bytewise) array into a wordwise array.
4579
* Find the longest run of 0x00's in src[] for :: shorthanding.
4581
memset(words, '\0', sizeof words);
4582
for (i = 0; i < NS_IN6ADDRSZ; i++)
4583
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
4586
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
4587
if (words[i] == 0) {
4589
cur.base = i, cur.len = 1;
4593
if (cur.base != -1) {
4594
if (best.base == -1 || cur.len > best.len)
4600
if (cur.base != -1) {
4602
if (best.base == -1 || cur.len > best.len)
4605
if (best.base != -1 && best.len < 2)
4609
* Format the result.
4612
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
4613
/* Are we inside the best run of 0x00's? */
4614
if (best.base != -1 && i >= best.base &&
4615
i < (best.base + best.len)) {
4620
/* Are we following an initial run of 0x00s or any real hex? */
4623
/* Is this address an encapsulated IPv4? */
4624
if (i == 6 && best.base == 0 &&
4625
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
4626
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
4631
tp += sprintf(tp, "%x", words[i]);
4633
/* Was it a trailing run of 0x00's? */
4634
if (best.base != -1 && (best.base + best.len) ==
4635
(NS_IN6ADDRSZ / NS_INT16SZ))
4640
* Check for overflow, copy, and we're done.
4642
if ((size_t)(tp - tmp) > size) {
4650
const char *inet_ntop(int af, const void *src, char *dst, size_t size) {
4653
return (inet_ntop4(src, dst, size));
4655
return (inet_ntop6(src, dst, size));
4665
/* *************************************************** */
4667
u_int numActiveNxPorts (u_int deviceId) {
4668
u_int numSenders = 0;
4671
for(el=getFirstHost(deviceId);
4672
el != NULL; el = getNextHost(deviceId, el)) {
4673
if (isFcHost (el) && (el->hostFcAddress.domain == FC_ID_SYSTEM_DOMAIN))
4682
/* *************************************** */
4684
#if 0 /* Not used */
4685
HostTraffic* findHostByFcAddr(FcAddress *fcAddr, u_short vsanId, u_int actualDeviceId) {
4687
u_int idx = hashFcHost(fcAddr, vsanId, &el, actualDeviceId);
4690
return(el); /* Found */
4691
else if(idx == FLAG_NO_PEER)
4694
el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
4696
for(; el != NULL; el = el->next) {
4697
if((el->hostFcAddress.domain != 0) && (!memcmp(&el->hostFcAddress, &fcAddr, LEN_FC_ADDRESS)))
4705
/* *************************************** */
4707
FcNameServerCacheEntry *findFcHostNSCacheEntry(FcAddress *fcAddr, u_short vsanId) {
4708
FcNameServerCacheEntry *entry = NULL;
4709
HostTraffic *el = NULL;
4710
u_int hashIdx = hashFcHost(fcAddr, vsanId, &el, -1);
4712
entry = myGlobals.fcnsCacheHash[hashIdx];
4714
while (entry != NULL) {
4715
if ((entry->vsanId == vsanId) &&
4716
(memcmp ((u_int8_t *)fcAddr, (u_int8_t *)&entry->fcAddress,
4717
LEN_FC_ADDRESS) == 0))
4720
entry = entry->next;
4726
/* ************************************ */
4729
/* HTTP version file retrieval loosely based on wget from FSF
4731
* Retrieve a document through HTTP protocol.
4734
* <site>www.ntop.org</site>
4735
* <stable>2.2c</stable>
4736
* <development>2.2.97</development>
4737
* <unsupported>2.2</unsupported>
4740
* However, this is very unsopisticated. If there's any problem, something
4741
* we don't expect, etc., just report it and move on...
4745
/* ********************************** */
4747
/* First a bunch of helper functions to keep the main checkVersion() routine
4748
* even slightly understandable...
4751
unsigned int convertNtopVersionToNumber(char *versionString) {
4752
/* This one is purely an arbitrary conversion.
4754
* But it knows about the version # schemes we've used in the past
4755
* e.g. 2.2c, 2.2.50, 2.2.97, 3.0pre1, 3.0rc1 etc. so that the number truly is relative
4756
* for numeric testing.
4758
* The goal is to get the following converted to ascending numeric order:
4760
* 1.3 2.1 2.1.2 2.1.3 2.1.50 2.1.90 2.2 2.2a 2.2b 2.2c 2.2.50 2.2.97 3.0pre1 3.0rc1 3.0
4783
* n.m.x -> nmmyyy0xx (if x>=50 yyy=x else xx=x)
4784
* n.ml -> nmm000l00 (where a=1, b=2, etc.)
4786
unsigned int f, n=0, m=0, x=0, y=0, c=0, prerc=0;
4789
if (versionString == NULL) {
4793
memset(&l, 0, sizeof(l));
4795
f = sscanf(versionString, "%u.%upre%u", &n, &m, &x);
4799
f = sscanf(versionString, "%u.%urc%u", &n, &m, &x);
4803
f = sscanf(versionString, "%u.%u%1[a-z].%u", &n, &m, &l, &x);
4806
l[0] = tolower(l[0]) - 'a' + 1;
4808
memset(&l, 0, sizeof(l));
4809
f = sscanf(versionString, "%u.%u.%u", &n, &m, &x);
4821
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: %s is n%u m%u y%u l%u x%u prerc%u f=%u",
4822
versionString, n, m, y, l[0], x, prerc, f);
4824
return n*100000000 + m*1000000 + y*1000 + l[0]*100 + x - 1000*prerc;
4827
/* ********************************** */
4829
void displayPrivacyNotice(void) {
4832
/* globals.displayPrivacyNotice:
4834
* 0 (or not present) means display one-time
4835
* 1 means already displayed
4836
* 2 means display every time
4838
if(fetchPrefsValue("globals.displayPrivacyNotice", value, sizeof(value)) == -1) {
4844
storePrefsValue("globals.displayPrivacyNotice", "1");
4845
/* NO BREAK HERE... fall into next case so we do the one-time display */
4847
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4848
"CHKVER: **********************PRIVACY**NOTICE**********************");
4849
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4850
"CHKVER: * ntop instances may record individually identifiable *");
4851
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4852
"CHKVER: * information on a remote system as part of the version *");
4853
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4854
"CHKVER: * check. *");
4855
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4857
if(myGlobals.skipVersionCheck == TRUE) {
4858
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4859
"CHKVER: * You have requested - via the --skip-version-check *");
4860
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4861
"CHKVER: * option that this check be skipped and so no *");
4862
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4863
"CHKVER: * individually identifiable information will be recorded. *");
4865
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4866
"CHKVER: * You may request - via the --skip-version-check option *");
4867
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4868
"CHKVER: * that this check be skipped and that no individually *");
4869
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4870
"CHKVER: * identifiable information be recorded. *");
4872
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4874
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4875
"CHKVER: * In general, we ask you to permit this check because it *");
4876
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4877
"CHKVER: * benefits both the users and developers of ntop. *");
4878
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4880
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4881
"CHKVER: * Review the man ntop page for more information. *");
4882
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4884
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
4885
"CHKVER: **********************PRIVACY**NOTICE**********************");
4889
// Enable this only if you suspect the conversion is hosed, to collect
4890
// information for the ntop-dev mailing list.
4891
// Normally you would enable this, run ntop, collect the values and
4892
// then shut ntop down.
4893
#define cNV2N(a, b) \
4896
vv = convertNtopVersionToNumber(a); \
4898
traceEvent(CONST_TRACE_INFO, "CHKVER_TEST: cNV2N %-10s -> %10u expected %10u", a, vv, b); \
4900
traceEvent(CONST_TRACE_INFO, "CHKVER_TEST: cNV2N %-10s -> %10u OK", a, vv); \
4903
cNV2N("1.3", 103000000);
4904
cNV2N("2.1", 201000000);
4905
cNV2N("2.1.1", 201000001);
4906
cNV2N("2.1.2", 201000002);
4907
cNV2N("2.1.3", 201000003);
4908
cNV2N("2.1.50", 201050000);
4909
cNV2N("2.1.90", 201090000);
4910
cNV2N("2.2", 202000000);
4911
cNV2N("2.2a", 202000100);
4912
cNV2N("2.2b", 202000200);
4913
cNV2N("2.2c", 202000300);
4914
cNV2N("2.2c.1", 202000301);
4915
cNV2N("2.2.50", 202050000);
4916
cNV2N("2.2.90", 202090000);
4917
cNV2N("3.0pre1", 299998001);
4918
cNV2N("3.0pre10",299998010);
4919
cNV2N("3.0rc1", 299999001);
4920
cNV2N("3.0rc2", 299999002);
4921
cNV2N("3.0rc14", 299999014);
4922
cNV2N("3.0", 300000000);
4926
/* ********************************** */
4928
/* Externally exposed function to turn the code into words... */
4929
char *reportNtopVersionCheck(void) {
4930
switch(myGlobals.checkVersionStatus) {
4931
case FLAG_CHECKVERSION_NOTCHECKED:
4932
return "was not checked";
4933
case FLAG_CHECKVERSION_OBSOLETE:
4934
return "an OBSOLETE and UNSUPPORTED version - please upgrade";
4935
case FLAG_CHECKVERSION_UNSUPPORTED:
4936
return "an UNSUPPORTED version - please upgrade";
4937
case FLAG_CHECKVERSION_NOTCURRENT:
4938
return "a minimally supported but OLDER version - please upgrade";
4939
case FLAG_CHECKVERSION_CURRENT:
4940
return "the CURRENT stable version";
4941
case FLAG_CHECKVERSION_OLDDEVELOPMENT:
4942
return "an unsupported old DEVELOPMENT version - upgrade";
4943
case FLAG_CHECKVERSION_DEVELOPMENT:
4944
return "the current DEVELOPMENT version - Expect the unexpected!";
4945
case FLAG_CHECKVERSION_NEWDEVELOPMENT:
4946
return "a new DEVELOPMENT version - Be careful!";
4948
return "is UNKNOWN...";
4952
/* ********************************** */
4954
/* pseudo-function to use stringification to find the xml tag */
4955
#define xmlextract(a) { \
4956
a = strstr(next, "<" #a ">"); \
4958
a += sizeof( #a ) + 1; \
4959
if (strchr(a, '<') != NULL) \
4960
strchr(a, '<')[0] = '\0'; \
4964
/* ********************************** */
4966
void tokenizeCleanupAndAppend(char *userAgent, int userAgentLen,
4967
char *title, char *input) {
4973
strncat(userAgent, " ", (userAgentLen - strlen(userAgent) - 1));
4974
strncat(userAgent, title, (userAgentLen - strlen(userAgent) - 1));
4975
strncat(userAgent, "(", (userAgentLen - strlen(userAgent) - 1));
4977
token = strtok(work, " \t\n");
4978
while (token != NULL) {
4980
/* No -? then it's a data value - skip */
4981
if(token[0] != '-') {
4982
token = strtok(NULL, " \t\n");
4986
/* Skip -s, end at = */
4987
for(j=i=0; i<strlen(token); i++) {
4988
if(token[i] == '=') {
4989
token[j++] = token[i]; /* we preserve the = so we know it was used,
4990
but drop the data value */
4992
} else if(token[i] != '-')
4993
token[j++] = token[i];
4997
if(strncmp(token, "without", strlen("without")) == 0)
4998
token += strlen("without");
4999
if(strncmp(token, "with", strlen("with")) == 0)
5000
token += strlen("with");
5001
if(strncmp(token, "disable", strlen("disable")) == 0)
5002
token += strlen("disable");
5003
if(strncmp(token, "enable", strlen("enable")) == 0)
5004
token += strlen("enable");
5006
if((strncmp(token, "prefix", strlen("prefix")) != 0) &&
5007
(strncmp(token, "sysconfdir", strlen("sysconfdir")) != 0) &&
5008
(strncmp(token, "norecursion", strlen("norecursion")) != 0)) {
5010
strncat(userAgent, "; ", (userAgentLen - strlen(userAgent) - 1));
5011
strncat(userAgent, token, (userAgentLen - strlen(userAgent) - 1));
5014
token = strtok(NULL, " \t\n");
5016
strncat(userAgent, ")", (userAgentLen - strlen(userAgent) - 1));
5021
/* ********************************** */
5023
void extractAndAppend(char *userAgent, int userAgentLen,
5024
char *title, char *input) {
5026
int i, j, dFlag=FALSE;
5030
for(j=i=0; i<strlen(work); i++) {
5031
if (dFlag == TRUE) {
5032
if((work[i] == ' ') ||
5033
(work[i] == ',') ) {
5037
} else if (isdigit(work[i])) {
5044
strncat(userAgent, " ", (userAgentLen - strlen(userAgent) - 1));
5045
strncat(userAgent, title, (userAgentLen - strlen(userAgent) - 1));
5046
strncat(userAgent, "/", (userAgentLen - strlen(userAgent) - 1));
5047
strncat(userAgent, work, (userAgentLen - strlen(userAgent) - 1));
5053
/* ********************************** */
5055
/* ===== ===== retrieve url ===== ===== */
5057
int retrieveVersionFile(char *versionSite, char *versionFile, char *buf, int bufLen) {
5058
struct hostent *hptr;
5059
char *userAgent, *space;
5061
struct sockaddr_in addr;
5062
#ifdef HAVE_SYS_UTSNAME_H
5063
struct utsname unameData;
5066
/* Establish the connection */
5067
hptr = gethostbyname(versionSite);
5069
traceEvent(CONST_TRACE_ERROR, "CHKVER: Unable to resolve site %s", versionSite);
5073
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Site resolved to %u.%u.%u.%u",
5074
(hptr->h_addr)[0] & 0xff,
5075
(hptr->h_addr)[1] & 0xff,
5076
(hptr->h_addr)[2] & 0xff,
5077
(hptr->h_addr)[3] & 0xff);
5080
/* Create socket for http GET */
5081
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
5083
traceEvent(CONST_TRACE_ERROR,
5084
"CHKVER: Unable to create socket: %s(%d)", strerror(errno), errno);
5088
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Socket is %d", sock);
5091
memset(&addr, 0, sizeof(addr));
5092
addr.sin_family = AF_INET;
5093
addr.sin_port = htons(80);
5094
memcpy((char *) &addr.sin_addr.s_addr, hptr->h_addr_list[0], hptr->h_length);
5096
/* Connect the socket to the remote host. */
5097
rc = connect(sock, (struct sockaddr*)&addr, (socklen_t) sizeof(addr));
5099
traceEvent(CONST_TRACE_ERROR,
5100
"CHKVER: Unable to connect socket: %s(%d)", strerror(errno), errno);
5105
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Connected");
5108
userAgent=malloc(LEN_GENERAL_WORK_BUFFER);
5109
memset(userAgent, 0, LEN_GENERAL_WORK_BUFFER);
5110
if(snprintf(userAgent, LEN_GENERAL_WORK_BUFFER, "ntop/%s", version) < 0)
5113
/* Convert any spaces in the version to +s
5114
* e.g. 2.2.98 0300 -> 2.2.98+0300
5116
while ((space=strchr(userAgent, ' ')) != NULL) {
5120
strncat(userAgent, " host/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5121
strncat(userAgent, osName, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5123
if((distro != NULL) && (strcmp(distro, "") != 0)) {
5124
strncat(userAgent, " distro/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5125
strncat(userAgent, distro, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5128
if((release != NULL) && (strcmp(release, "") != 0) && (strcmp(release, "unknown") != 0)) {
5129
strncat(userAgent, " release/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5130
strncat(userAgent, release, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5133
#ifdef HAVE_SYS_UTSNAME_H
5134
if (uname(&unameData) == 0) {
5135
strncat(userAgent, " kernrlse/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5136
strncat(userAgent, unameData.release, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5141
/* Macros to kludge around stringing of parameters */
5142
#define xstr(s) str(s)
5145
#if defined(__GNUC_PATCHLEVEL__)
5146
#define GCC_VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
5148
#define GCC_VERSION __GNUC__.__GNUC_MINOR__
5150
strncat(userAgent, " GCC/" xstr(GCC_VERSION) , (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5156
tokenizeCleanupAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "config", configure_parameters);
5157
tokenizeCleanupAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "run", myGlobals.startedAs);
5159
#ifdef HAVE_PCAP_LIB_VERSION
5160
extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "libpcap", (char*)pcap_lib_version());
5163
#if defined(WIN32) && defined(__GNUC__)
5164
/* on mingw, gdbm_version not exported by library */
5166
extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "gdbm", gdbm_version);
5170
* If we've guessed at the gd version, report it
5172
if(myGlobals.gdVersionGuessValue != NULL)
5173
extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "gd", myGlobals.gdVersionGuessValue);
5176
extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "openssl", (char*)SSLeay_version(0));
5179
extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "zlib", (char*)zlibVersion());
5181
/* Special case for webPort+sslPort... */
5182
strncat(userAgent, " access/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5184
if (myGlobals.sslPort != 0) {
5185
if(myGlobals.webPort != 0)
5186
strncat(userAgent, "both", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5188
strncat(userAgent, "https", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5191
if(myGlobals.webPort != 0)
5192
strncat(userAgent, "http", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5194
strncat(userAgent, "none", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5196
/* Special case for interfaces */
5197
strncat(userAgent, " interfaces(", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5198
if(myGlobals.devices != NULL) {
5199
strncat(userAgent, myGlobals.devices, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5201
strncat(userAgent, "null", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5203
strncat(userAgent, ")", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
5205
if(snprintf(buf, bufLen, "GET /%s HTTP/1.0\r\n"
5207
"User-Agent: %s\r\n"
5213
CONST_HTTP_ACCEPT_ALL) < 0)
5218
/* Send the request to server. */
5219
traceEvent(CONST_TRACE_NOISY, "CHKVER: Sending request: %s", buf);
5220
rc = send(sock, buf, strlen(buf), 0);
5222
traceEvent(CONST_TRACE_ERROR,
5223
"CHKVER: Unable to send http request: %s(%d)", strerror(errno), errno);
5228
/* Pickup the response -
5229
* remember, buf/bufLen better be big enough to handle the whole response
5231
memset(buf, 0, bufLen);
5232
rc = recv(sock, buf, bufLen,
5240
traceEvent(CONST_TRACE_ERROR,
5241
"CHKVER: Unable to receive http response: %s(%d)", strerror(errno), errno);
5246
traceEvent(CONST_TRACE_ERROR,
5247
"CHKVER: Unable to receive entire http response (%d/%d)- skipping",
5255
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Received %d bytes '%s'", rc, buf);
5261
/* ********************************** */
5263
int processVersionFile(char *buf, int bufLen) {
5264
/* Process the returned data
5265
* We march through the big buffer,
5266
* with hdr pointing at a C string for each header
5267
* and next pointing at the next character we pick up with.
5270
int i, j, k, rc, hcount=0;
5271
unsigned int sNumber, dNumber, uNumber, oNumber, vNumber;
5272
char *hdr, *next, *site, *date, *development, *stable, *unsupported, *obsolete;
5281
if (--bufLen <= 0) {
5282
traceEvent(CONST_TRACE_ERROR, "CHKVER: Past end processing http response");
5285
/* Cleanup whitespace */
5286
if (hdr[i] == '\r' ||
5292
if(hdr[i] == '\n') {
5295
/* Check for header continuation (not allowed on the 1st header)
5296
* by looking at the character ahead.
5299
(hdr[i+1] == '\t' || hdr[i+1] == ' ')) {
5303
/* Otherwise, set next... */
5306
/* Clear trailing whitespace... */
5308
while((i>=0) && (hdr[i]==' ')) hdr[i--]='\0';
5315
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: %3d. (%3d) '%s'", hcount, strlen(hdr), hdr);
5318
/* Check for rc line. */
5320
/* Parse the first line of server response */
5321
if (hdr[0] == '\0') {
5322
traceEvent(CONST_TRACE_ERROR, "CHKVER: http response: Nothing");
5326
* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
5329
while(hdr[0] != '\0') {
5336
while((hdr[0] != '\0') &&
5338
rc = 10*rc + hdr[0] - '0';
5342
traceEvent(CONST_TRACE_WARNING,
5343
"CHKVER: http response: %d - skipping check", rc);
5346
traceEvent(CONST_TRACE_NOISY, "CHKVER: http response: %d", rc);
5349
/* Empty? Done with the headers... */
5350
if (hdr[0] == '\0') {
5356
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: raw version file is %s", next);
5359
/* Cleanup whitespace */
5360
for (j=i=0; i<strlen(next); i++) {
5361
if(next[i] == '<' &&
5365
for(k=i+4; k<strlen(next)-3; k++) {
5366
if(next[k] == '-' &&
5373
if(k<strlen(next)-3)
5375
/* Otherwise, we never found the close... so we ignore the 'comment' */
5377
if(next[i] == '\n' ||
5384
next[j++] = next[i];
5390
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: cleaned version file is %s", next);
5393
/* parse - in reverse order so we can do it cheesy using \0s */
5394
xmlextract(development);
5396
xmlextract(unsupported);
5397
xmlextract(obsolete);
5401
vNumber = convertNtopVersionToNumber(version);
5402
oNumber = convertNtopVersionToNumber(obsolete);
5403
uNumber = convertNtopVersionToNumber(unsupported);
5404
sNumber = convertNtopVersionToNumber(stable);
5405
dNumber = convertNtopVersionToNumber(development);
5406
if((oNumber == 999999999) ||
5407
(uNumber == 999999999) ||
5408
(sNumber == 999999999) ||
5409
(dNumber == 999999999) ||
5410
(vNumber == 999999999) ||
5411
(oNumber > uNumber) ||
5412
(uNumber > sNumber) ||
5413
(sNumber > dNumber)) {
5414
traceEvent(CONST_TRACE_WARNING,
5415
"CHKVER: version file INVALID - ignoring version check");
5416
traceEvent(CONST_TRACE_WARNING,
5417
"CHKVER: Please report to ntop mailing list, codes (%u,%u,%u,%u,%u)",
5418
oNumber, uNumber, sNumber, dNumber, vNumber);
5422
traceEvent(CONST_TRACE_INFO, "CHKVER: Version file is from '%s'", site);
5423
traceEvent(CONST_TRACE_INFO, "CHKVER: as of date is '%s'", date);
5425
traceEvent(CONST_TRACE_NOISY, "CHKVER: obsolete is '%-10s' (%9u)", obsolete, oNumber);
5426
traceEvent(CONST_TRACE_NOISY, "CHKVER: unsupported is '%-10s' (%9u)", unsupported, uNumber);
5427
traceEvent(CONST_TRACE_NOISY, "CHKVER: stable is '%-10s' (%9u)", stable, sNumber);
5428
traceEvent(CONST_TRACE_NOISY, "CHKVER: development is '%-10s' (%9u)", development, dNumber);
5429
traceEvent(CONST_TRACE_NOISY, "CHKVER: version is '%-10s' (%9u)", version, vNumber);
5431
/* Check values - set status flag */
5432
if(vNumber < oNumber) {
5433
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_OBSOLETE;
5434
} else if(vNumber < uNumber) {
5435
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_UNSUPPORTED;
5436
} else if(vNumber < sNumber) {
5437
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_NOTCURRENT;
5438
} else if(vNumber == sNumber) {
5439
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_CURRENT;
5440
} else if(vNumber < dNumber) {
5441
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_OLDDEVELOPMENT;
5442
} else if(vNumber == dNumber) {
5443
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_DEVELOPMENT;
5445
myGlobals.checkVersionStatus = FLAG_CHECKVERSION_NEWDEVELOPMENT;
5451
/* ********************************** */
5453
void* checkVersion(void* notUsed _UNUSED_) {
5454
/* The work buffer is a big boy so we can eat the entire XML file all at once
5455
* and avoid making this logic any more complex!
5457
char buf[LEN_CHECKVERSION_BUFFER];
5460
displayPrivacyNotice();
5462
if(myGlobals.skipVersionCheck == TRUE)
5465
for(idx = 0; versionSite[idx] != NULL; idx++) {
5466
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
5467
"CHKVER: Checking current ntop version at %s/%s", versionSite[idx], CONST_VERSIONCHECK_DOCUMENT);
5470
traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: '%s' '%s'", versionSite[idx], CONST_VERSIONCHECK_DOCUMENT);
5473
memset(buf, 0, sizeof(buf));
5475
rc = retrieveVersionFile(versionSite[idx], CONST_VERSIONCHECK_DOCUMENT, buf, sizeof(buf));
5481
rc = processVersionFile(buf, min(sizeof(buf), strlen(buf)));
5484
traceEvent(CONST_TRACE_INFO,
5485
"CHKVER: This version of ntop is %s", reportNtopVersionCheck());
5489
if(myGlobals.checkVersionStatus != FLAG_CHECKVERSION_NEWDEVELOPMENT)
5490
/* If it was new development at the 1st check, it's not magically going
5491
* to become anything else... so don't report a recheck time
5493
myGlobals.checkVersionStatusAgain = time(NULL) + CONST_VERSIONRECHECK_INTERVAL;
5495
myGlobals.checkVersionStatusAgain = 0;
5500
/* ********************************** */
5502
int readInputFile(FILE* fd,
5505
u_char compressedFormat,
5512
* This is a common routine to return the records from a data file, compressed or
5513
* not, which was checked for via checkForInputFile.
5515
* It returns -1 if an eof occured or zero otherwise.
5516
* The record is returned in buf.
5518
* Call with forceClose TRUE to force the file to be closed...
5523
if((fd != NULL) && (forceClose == FALSE) && (buf != NULL) && (bufLen > 0)) {
5524
#ifdef MAKE_WITH_ZLIB
5525
if(compressedFormat)
5526
getValue = gzgets(fd, buf, bufLen);
5529
getValue = fgets(buf, bufLen, fd);
5531
if(getValue != NULL) {
5533
if((logTag != NULL) && (countPer > 0) && ((*recordsRead) % countPer == 0))
5534
traceEvent(CONST_TRACE_NOISY, "%s: ....%6d records read", logTag, (*recordsRead));
5539
/* Either EOF or forceClose */
5541
traceEvent(CONST_TRACE_NOISY, "%s: Closing file", logTag);
5544
#ifdef MAKE_WITH_ZLIB
5545
if(compressedFormat)
5551
if((logTag != NULL) && (*recordsRead > 0))
5552
traceEvent(CONST_TRACE_INFO, "%s: ...found %d lines", logTag, *recordsRead);
5557
/* ********************************** */
5559
FILE* checkForInputFile(char* logTag,
5562
struct stat *dbStat,
5563
u_char* compressedFormat) {
5565
int configFileFound=FALSE, idx;
5566
char tmpFile[LEN_GENERAL_WORK_BUFFER];
5569
char bufTime[LEN_TIMEFORMAT_BUFFER], bufTime2[LEN_TIMEFORMAT_BUFFER];
5572
* This is a common routine to look for a data file, compressed or not,
5573
* in the various locations ntop looks for them.
5575
* It returns fd if a file was found. Returned value compressedFormat tells the tale
5577
* It returns NULL if the file was not found.
5579
* If you only want to reload the file if it is newer, then pass
5580
* a populated stat structure in as dbStat, and it will be checked.
5582
* External to this you will not be able to tell the difference
5583
* between a NULL for not found and NULL for not newer - let this routine's
5584
* messages be enough for the user.
5586
if(logTag != NULL) traceEvent(CONST_TRACE_INFO, "%s: Checking for %s file", logTag, descr);
5587
for(idx=0; myGlobals.configFileDirs[idx] != NULL; idx++) {
5589
#ifdef MAKE_WITH_ZLIB
5590
*compressedFormat = 1;
5591
if(snprintf(tmpFile, sizeof(tmpFile),
5593
myGlobals.configFileDirs[idx], CONST_PATH_SEP, fileName) < 0)
5595
if(logTag != NULL) traceEvent(CONST_TRACE_NOISY, "%s: Checking '%s'", logTag, tmpFile);
5596
fd = gzopen(tmpFile, "r");
5597
/* Note, if this code is inactive, fd is NULL from above, avoids fancy ifdefs */
5601
*compressedFormat = 0;
5602
if(snprintf(tmpFile, sizeof(tmpFile),
5604
myGlobals.configFileDirs[idx], CONST_PATH_SEP, fileName) < 0)
5606
if(logTag != NULL) traceEvent(CONST_TRACE_NOISY, "%s: Checking '%s'", logTag, tmpFile);
5607
fd = fopen(tmpFile, "r");
5611
configFileFound = TRUE;
5612
if(logTag != NULL) traceEvent(CONST_TRACE_NOISY, "%s: ...Found", logTag);
5617
if (configFileFound != TRUE) {
5619
traceEvent(CONST_TRACE_WARNING, "%s: Unable to open file '%s'", logTag, fileName);
5624
struct stat checkStat;
5626
if(logTag != NULL) {
5627
memset(bufTime, 0, sizeof(bufTime));
5628
memset(bufTime2, 0, sizeof(bufTime2));
5629
strftime(bufTime, sizeof(bufTime), CONST_LOCALE_TIMESPEC,
5630
localtime_r(&(dbStat->st_ctime), &t));
5631
strftime(bufTime2, sizeof(bufTime2), CONST_LOCALE_TIMESPEC,
5632
localtime_r(&(dbStat->st_mtime), &t));
5633
traceEvent(CONST_TRACE_NOISY, "%s: Database created %s, last modified %s", logTag, bufTime, bufTime2);
5636
/* Check time stamps... */
5637
if(!stat(tmpFile, &checkStat)) {
5639
/* Pick the later - so if you copy/move a file we know it */
5640
compareTime = max(checkStat.st_ctime, checkStat.st_mtime);
5641
if(logTag != NULL) {
5642
memset(bufTime, 0, sizeof(bufTime));
5643
strftime(bufTime, sizeof(bufTime), CONST_LOCALE_TIMESPEC,
5644
localtime_r(&compareTime, &t));
5645
traceEvent(CONST_TRACE_NOISY, "%s: Input file created/last modified %s", logTag, bufTime);
5647
if(dbStat->st_mtime >= compareTime) {
5649
traceEvent(CONST_TRACE_INFO,"%s: File '%s' does not need to be reloaded", logTag, tmpFile);
5650
#ifdef MAKE_WITH_ZLIB
5651
if(*compressedFormat)
5659
traceEvent(CONST_TRACE_INFO, "%s: Loading newer file '%s'", logTag, tmpFile);
5662
if(logTag != NULL) {
5663
traceEvent(CONST_TRACE_WARNING,
5664
"%s: Unable to check file age %s(%d)",
5665
logTag, strerror(errno), errno);
5666
traceEvent(CONST_TRACE_INFO, "%s: File '%s' loading", logTag, tmpFile);
5671
traceEvent(CONST_TRACE_INFO, "%s: Loading file '%s'", logTag, tmpFile);
5676
/* ******************************************** */
5677
/* Fixup routines for ethernet addresses */
5679
void urlFixupFromRFC1945Inplace(char* url) {
5681
/* Do an in-place fixup of a rfc1945 URL back to the internal name,
5682
that is convert _s back to :s
5686
for(i=0; url[i] != '\0'; i++)
5692
void urlFixupToRFC1945Inplace(char* url) {
5694
/* Do an in-place fixup of an internal name to a RFC1945 URL,
5695
that is convert :s to _s
5699
for(i=0; url[i] != '\0'; i++)
5705
/* ********************************************* */
5707
void _setResolvedName(HostTraffic *el, char *updateValue, short updateType, char* file, int line) {
5710
if(updateValue[0] == '\0') return;
5712
/* Only update if this is a MORE important type */
5713
if(updateType > el->hostResolvedNameType) {
5715
#ifndef CMPFCTN_DEBUG
5716
if(myGlobals.debugMode == 1)
5718
traceEvent(CONST_TRACE_INFO,
5719
"CMPFCTN_DEBUG: setResolvedName(0x%08x) %d %s -> %d %s - %s(%d)",
5721
el->hostResolvedNameType,
5722
el->hostResolvedName,
5727
strncpy(el->hostResolvedName, updateValue, MAX_LEN_SYM_HOST_NAME-1);
5728
// el->hostResolvedName[MAX_LEN_SYM_HOST_NAME-1] = '\0';
5729
for(i=0; el->hostResolvedName[i] != '\0'; i++)
5730
el->hostResolvedName[i] = tolower(el->hostResolvedName[i]);
5732
el->hostResolvedNameType = updateType;
5736
/* ********************************************* */
5737
/* ********************************************* */
5738
/* hostResolvedName compare function */
5739
/* ********************************************* */
5741
int cmpFctnResolvedName(const void *_a, const void *_b) {
5743
/* This function is ugly, but critical, so bare with...
5745
It takes two HostTraffic entries and performs a standardized compare
5746
of the hostResolvedName fields, reaching into OTHER fields as necessary.
5748
The SOLE goal is to provide a stable comparison.
5750
Hopefully the results are PREDICTABLE and EXPLAINABLE, but that's totally
5753
Why? Because sorts don't handle non-transitive compares very well.
5755
If A>B but B !< A, the sort will probably CHOKE.
5757
Since the hostResolvedName field contains something like six or nine
5758
possible types of 'names' for a host, a simple alphabetic compare
5759
won't cut it. Especially as hostResolvedName may not be valued
5760
at the time of the compare...
5762
We also can't simply just use the next valued field in the
5763
sets, because we run the risk of intransitive compares,
5766
primary(a) > primary(b)
5770
secondary(a) < secondary(b)
5772
and if we have say primary for a and c, but not b, risk that
5773
just because a<b and b<c a !< c... this completely hoses the
5777
So instead in this routine, we practice a gracefull, explicit fallback:
5779
1. If the HostTraffic pointers are NULL, we return equality.
5781
1A. If one of the HostTraffic pointers is NULL, we return THAT entry as <
5783
2. If both of the hostResolvedName fields are NOT NULL,
5784
and both of the hostResolvedNameType fields are NONE, we:
5786
2A. Check the hostResolvedNameType fields for both A and B.
5788
2A1. If they are identical, we perform the approprate
5789
apples to apples compare.
5791
For example using hostNumIpAddress for a meaningful
5792
IP address sort (where 9.0.0.0 < 10.0.0.0).
5794
2A2. If the hostResolvedNameType fields are NOT identical, we
5795
do the sort on the hostResolvedNameType field itself.
5798
2A1+2A2 means that we sort all of the NAMES alphabetically,
5799
followed by all of the IP addresses sorted NUMERICALLY, followed by...
5801
3A. If precisely ONE of the hostResolvedName fields is NULL or precisely ONE
5802
of the hostResolvedNameType fields is NONE, we return the
5803
valued field < the unvalued one (so unresolved things fall to the
5806
3B. If both of the hostResolvedName fields are NULL, we fall back
5807
gracefully, seeking - in the order of the _TYPE flags, a field which
5808
is valued in BOTH a and b.
5810
4. Finally if nothing matches, we return a=b.
5814
HostTraffic **a = (HostTraffic **)_a;
5815
HostTraffic **b = (HostTraffic **)_b;
5817
char *name1, *name2;
5818
#ifdef CMPFCTN_DEBUG
5819
char debugCmpFctn[128];
5820
memset(debugCmpFctn, 0, sizeof(debugCmpFctn));
5824
if((a == NULL) && (b == NULL)) {
5826
} else if(a == NULL) {
5828
} else if(b == NULL) {
5832
if((*a == NULL) && (*b == NULL)) {
5834
} else if(*a == NULL) {
5836
} else if(*b == NULL) {
5840
accessAddrResMutex("cmpFctnResolvedName");
5842
if(((*a)->hostResolvedName != NULL) &&
5843
((*a)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_NONE) &&
5844
((*b)->hostResolvedName != NULL) &&
5845
((*b)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_NONE)) {
5847
#ifdef CMPFCTN_DEBUG
5848
traceEvent(CONST_TRACE_INFO, "CMPFCTN_DEBUG: cmpFctn(0x%08x, 0x%08x): %d %s vs %d %s",
5851
(*a)->hostResolvedNameType,
5852
(*a)->hostResolvedName,
5853
(*b)->hostResolvedNameType,
5854
(*b)->hostResolvedName);
5857
/* 2 - valid hostResolvedName */
5858
if((*a)->hostResolvedNameType == (*b)->hostResolvedNameType) {
5861
/* Remember, order of the cases is important don't change
5862
* But also remember, we're comparing only the values of the
5863
* same type stored in hostResolvedName so MOST can be
5864
* a straight string compare.
5867
if((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_NAME) {
5868
name1 = (*a)->hostResolvedName;
5869
name2 = (*b)->hostResolvedName;
5870
rc = strcasecmp(name1, name2);
5871
#ifdef CMPFCTN_DEBUG
5872
strncpy(debugCmpFctn, "2A1-NAME", sizeof(debugCmpFctn));
5874
} else if((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_IP) {
5875
rc = addrcmp(&((*a)->hostIpAddress), &((*b)->hostIpAddress));
5876
#ifdef CMPFCTN_DEBUG
5877
strncpy(debugCmpFctn, "2A1-IP", sizeof(debugCmpFctn));
5879
} else if((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_MAC) {
5881
* Remember - the MAC value in hostResolvedName, is proabably the
5882
* translated MAC, e.g. 3COM CORPORATION:E2:DB:06 and not the
5883
* 48bit value. But, if we don't recognize the vendor, then it's the
5884
* 17 character form (xx:xx:xx:xx:xx:xx). The special case is to
5885
* sort xx: form AFTER the recognized ones.
5886
* We use strncasecmp so 3Com and 3COM sort together
5888
name1 = (*a)->hostResolvedName;
5889
name2 = (*b)->hostResolvedName;
5890
if(((name1[2] == ':') && (name2[2] != ':')) ||
5891
((name1[2] != ':') && (name2[2] == ':'))) {
5892
/* One : one recognized */
5893
if(name1[2] == ':') {
5894
rc=1; /* name1 (unrecognized) > name2 (recognized) */
5895
#ifdef CMPFCTN_DEBUG
5896
strncpy(debugCmpFctn, "2A1-MAC-1:", sizeof(debugCmpFctn));
5899
rc=-1; /* name1 (recognized) > name2 (unrecognized) */
5900
#ifdef CMPFCTN_DEBUG
5901
strncpy(debugCmpFctn, "2A1-MAC-2:", sizeof(debugCmpFctn));
5905
rc = strcasecmp(name1, name2);
5906
#ifdef CMPFCTN_DEBUG
5907
strncpy(debugCmpFctn, "2A1-MAC", sizeof(debugCmpFctn));
5910
} else if(((*a)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_FC) &&
5911
((*a)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_FAKE)) {
5912
/* For most of the rest of the tests, we just compare the names we
5913
* have - since they're always the same type, a strncasecmp test
5916
name1 = (*a)->hostResolvedName;
5917
name2 = (*b)->hostResolvedName;
5918
rc = strcasecmp(name1, name2);
5919
#ifdef CMPFCTN_DEBUG
5920
strncpy(debugCmpFctn, "2A1-!FC!FAKE", sizeof(debugCmpFctn));
5922
} else if((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_FC) {
5923
name1 = (*a)->hostResolvedName;
5924
name2 = (*b)->hostResolvedName;
5925
rc = strcasecmp(name1, name2);
5926
#ifdef CMPFCTN_DEBUG
5927
strncpy(debugCmpFctn, "2A1-FC", sizeof(debugCmpFctn));
5930
name1 = (*a)->hostResolvedName;
5931
name2 = (*b)->hostResolvedName;
5932
rc = strcasecmp(name1, name2);
5933
#ifdef CMPFCTN_DEBUG
5934
strncpy(debugCmpFctn, "2A1-FAKE", sizeof(debugCmpFctn));
5938
/* 2A2 - unequal types, so just compare the Type field */
5939
if((*a)->hostResolvedNameType > (*b)->hostResolvedNameType)
5940
rc = -1; /* Higher type before lower */
5943
#ifdef CMPFCTN_DEBUG
5944
strncpy(debugCmpFctn, "2A2!=", sizeof(debugCmpFctn));
5948
/* If only one is not NULL/NONE, so let's do 3A */
5949
if(((*a)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_NONE) &&
5950
((*b)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_NONE)) {
5951
/* a not NULL so return a<b */
5953
#ifdef CMPFCTN_DEBUG
5954
strncpy(debugCmpFctn, "3A-a!", sizeof(debugCmpFctn));
5956
} else if(((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_NONE) &&
5957
((*b)->hostResolvedNameType != FLAG_HOST_SYM_ADDR_TYPE_NONE)) {
5958
/* b not NULL so return a>b */
5960
#ifdef CMPFCTN_DEBUG
5961
strncpy(debugCmpFctn, "3A-b!", sizeof(debugCmpFctn));
5964
/* 3B - hostResolvedName not set - graceful fallback using the raw fields! */
5965
char nullEthAddress[LEN_ETHERNET_ADDRESS];
5966
memset(&nullEthAddress, 0, LEN_ETHERNET_ADDRESS);
5968
/* Do we have a non 0.0.0.0 IP? Yes: Compare it */
5969
if(!addrnull(&(*a)->hostIpAddress) &&
5970
!addrnull(&(*b)->hostIpAddress)) {
5971
rc = addrcmp(&((*a)->hostIpAddress), &((*b)->hostIpAddress));
5972
#ifdef CMPFCTN_DEBUG
5973
strncpy(debugCmpFctn, "3B-IP", sizeof(debugCmpFctn));
5976
} else if((memcmp((*a)->ethAddress, nullEthAddress, LEN_ETHERNET_ADDRESS) != 0) &&
5977
(memcmp((*b)->ethAddress, nullEthAddress, LEN_ETHERNET_ADDRESS) != 0)) {
5978
/* We have a non zero MAC - compare it */
5979
rc = memcmp(((*a)->ethAddress), ((*b)->ethAddress), LEN_ETHERNET_ADDRESS);
5980
#ifdef CMPFCTN_DEBUG
5981
strncpy(debugCmpFctn, "3B-MAC", sizeof(debugCmpFctn));
5984
} else if(((*a)->nonIPTraffic != NULL) && ((*b)->nonIPTraffic != NULL)) {
5985
/* Neither a nor b are null, so we can compare the fields in nonIPTraffic...
5986
* NetBIOS, IPX then Appletalk, if we have 'em */
5987
if(((*a)->nonIPTraffic->nbHostName != NULL) &&
5988
((*b)->nonIPTraffic->nbHostName != NULL)) {
5989
rc=strcasecmp((*a)->nonIPTraffic->nbHostName, (*b)->nonIPTraffic->nbHostName);
5990
#ifdef CMPFCTN_DEBUG
5991
strncpy(debugCmpFctn, "3B-NB", sizeof(debugCmpFctn));
5993
} else if(((*a)->nonIPTraffic->ipxHostName != NULL) &&
5994
((*b)->nonIPTraffic->ipxHostName != NULL)) {
5995
rc=strcasecmp((*a)->nonIPTraffic->ipxHostName, (*b)->nonIPTraffic->ipxHostName);
5996
#ifdef CMPFCTN_DEBUG
5997
strncpy(debugCmpFctn, "3B-IPX", sizeof(debugCmpFctn));
5999
} else if(((*a)->nonIPTraffic->atNodeName != NULL) &&
6000
((*b)->nonIPTraffic->atNodeName != NULL)) {
6001
rc=strcasecmp((*a)->nonIPTraffic->atNodeName, (*b)->nonIPTraffic->atNodeName);
6002
#ifdef CMPFCTN_DEBUG
6003
strncpy(debugCmpFctn, "3B-ATALK", sizeof(debugCmpFctn));
6006
rc=0; /* can't tell 'em apart... trouble */
6007
#ifdef CMPFCTN_DEBUG
6008
strncpy(debugCmpFctn, "3B-0", sizeof(debugCmpFctn));
6011
} else if(((*a)->nonIPTraffic == NULL) && ((*b)->nonIPTraffic != NULL)) {
6012
/* a null, b not so return a>b */
6014
#ifdef CMPFCTN_DEBUG
6015
strncpy(debugCmpFctn, "3B-b!", sizeof(debugCmpFctn));
6017
} else if(((*a)->nonIPTraffic != NULL) && ((*b)->nonIPTraffic == NULL)) {
6018
/* b null, a not so return a>b */
6020
#ifdef CMPFCTN_DEBUG
6021
strncpy(debugCmpFctn, "3B-a!", sizeof(debugCmpFctn));
6024
rc=0; /* nothing we can compare */
6025
#ifdef CMPFCTN_DEBUG
6026
strncpy(debugCmpFctn, "3B-null", sizeof(debugCmpFctn));
6032
releaseAddrResMutex();
6034
#ifdef CMPFCTN_DEBUG
6035
traceEvent(CONST_TRACE_INFO, "CMPFCTN_DEBUG: cmpFctn(): %s rc=%d", debugCmpFctn, rc);
6041
/* ********************************************* */
6042
/* ********************************************* */
6043
/* Location code compare function */
6044
/* ********************************************* */
6046
int cmpFctnLocationName(const void *_a, const void *_b) {
6048
/* This function takes two HostTraffic entries and performs a
6049
standardized compare of the location, either the ip2ccValue field
6050
or the fallback dnsTLDValue fields, handling unvalued
6051
situations to provide a stable comparison.
6053
We translate 'loc' (rfc1918 addresses) to sort next to last
6054
and unvalued items to sort last.
6056
Equal valued names are sorted based first on full domain name, then
6057
on hostResolvedName as the tie breakers.
6060
HostTraffic **a = (HostTraffic **)_a;
6061
HostTraffic **b = (HostTraffic **)_b;
6063
char *nameA, *nameB;
6067
if((*a)->ip2ccValue == NULL) {
6069
} else if(strcasecmp((*a)->ip2ccValue, "loc") == 0) {
6072
nameA = (*a)->ip2ccValue;
6074
if((*b)->ip2ccValue == NULL) {
6076
} else if(strcasecmp((*b)->ip2ccValue, "loc") == 0) {
6079
nameB = (*b)->ip2ccValue;
6082
rc = strcasecmp(nameA, nameB);
6084
if((*a)->dnsTLDValue == NULL) {
6087
nameA = (*a)->dnsTLDValue;
6089
if((*b)->dnsTLDValue == NULL) {
6092
nameB = (*b)->ip2ccValue;
6094
rc = strcasecmp(nameA, nameB);
6098
rc=cmpFctnResolvedName(a, b);
6104
/* ************************************ */