~ubuntu-branches/ubuntu/natty/ntop/natty

« back to all changes in this revision

Viewing changes to util.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2005-01-30 21:59:13 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050130215913-xc3ke963bw49b3k4
Tags: 2:3.0-5
* Updated README.Debian file so users will understand what to do at
  install, closes: #291794, #287802.
* Updated ntop init script to give better output.
* Also changed log directory from /var/lib/ntop to /var/log/ntop,
  closes: #252352.
* Quoted the interface list to allow whitespace, closes: #267248.
* Added a couple of logcheck ignores, closes: #269321, #269319.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
3
 *                          http://www.ntop.org
 
4
 *
 
5
 * Copyright (C) 1998-2004 Luca Deri <deri@ntop.org>
 
6
 *
 
7
 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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.
 
22
 */
 
23
 
 
24
#include "ntop.h"
 
25
#include <stdarg.h>
 
26
 
 
27
/* #define ADDRESS_DEBUG */
 
28
 
 
29
#ifdef MEMORY_DEBUG
 
30
#include "leaks.h"
 
31
#endif
 
32
 
 
33
#ifdef DARWIN
 
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();
 
42
#endif
 
43
 
 
44
#ifdef CFG_MULTITHREADED
 
45
static char stateChangeMutexInitialized = 0;
 
46
static pthread_mutex_t stateChangeMutex;
 
47
#endif
 
48
 
 
49
static SessionInfo *passiveSessions;
 
50
static u_short passiveSessionsLen;
 
51
 
 
52
static char *versionSite[]   = { 
 
53
  CONST_VERSIONCHECK_SITE,
 
54
  CONST_VERSIONCHECK_BACKUP_SITE,
 
55
  NULL };
 
56
 
 
57
/* ************************************ */
 
58
 
 
59
static HostTraffic* _getFirstHost(u_int actualDeviceId, u_int beginIdx) {
 
60
  u_int idx;
 
61
 
 
62
  for(idx=beginIdx; idx<myGlobals.device[actualDeviceId].actualHashSize; idx++) {
 
63
    HostTraffic *el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
64
 
 
65
    if(el != NULL) {
 
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);
 
69
      }
 
70
 
 
71
      return(el);
 
72
    }
 
73
  }
 
74
 
 
75
  return(NULL);
 
76
}
 
77
 
 
78
/* ************************************ */
 
79
 
 
80
HostTraffic* getFirstHost(u_int actualDeviceId) {
 
81
  return(_getFirstHost(actualDeviceId, FIRST_HOSTS_ENTRY));
 
82
}
 
83
 
 
84
/* ************************************ */
 
85
 
 
86
HostTraffic* getNextHost(u_int actualDeviceId, HostTraffic *host) {
 
87
  if(host == NULL) return(NULL);
 
88
 
 
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);
 
93
    }
 
94
 
 
95
    return(host->next);
 
96
  } else {
 
97
    u_int nextIdx = host->hostTrafficBucket+1;
 
98
 
 
99
    if(nextIdx < myGlobals.device[actualDeviceId].actualHashSize)
 
100
      return(_getFirstHost(actualDeviceId, nextIdx));
 
101
    else
 
102
      return(NULL);
 
103
  }
 
104
}
 
105
 
 
106
/* ************************************ */
 
107
 
 
108
HostTraffic* findHostByNumIP(HostAddr hostIpAddress, u_int actualDeviceId) {
 
109
  HostTraffic *el;
 
110
  short dummyShort=1;
 
111
  u_int idx = hashHost(&hostIpAddress, NULL, &dummyShort, &el, actualDeviceId);
 
112
 
 
113
  if(el != NULL)
 
114
    return(el); /* Found */
 
115
  else if(idx == FLAG_NO_PEER)
 
116
    return(NULL);
 
117
  else
 
118
    el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
119
 
 
120
  for(; el != NULL; el = el->next) {
 
121
    if((el->hostNumIpAddress != NULL) && (addrcmp(&el->hostIpAddress,&hostIpAddress) == 0))
 
122
      return(el);
 
123
  }
 
124
 
 
125
  if(el == NULL) {
 
126
    /*
 
127
      Fallback:
 
128
      probably a local host has been searched using an IP
 
129
      address (we should have used a MAC)
 
130
    */
 
131
 
 
132
    for(idx=0; idx<myGlobals.device[actualDeviceId].actualHashSize; idx++) {
 
133
      el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
134
 
 
135
      for(; el != NULL; el = el->next) {
 
136
        if((el->hostNumIpAddress != NULL) && (addrcmp(&el->hostIpAddress,&hostIpAddress) == 0))
 
137
          return(el);
 
138
      }
 
139
    }  }
 
140
 
 
141
#ifdef DEBUG
 
142
  {
 
143
    char buf[48];
 
144
 
 
145
    traceEvent(CONST_TRACE_NOISY, "==>>> Unable to locate host %s",
 
146
               _intoa(hostIpAddress, buf, sizeof(buf)));
 
147
  }
 
148
#endif
 
149
 
 
150
  return(NULL);
 
151
}
 
152
 
 
153
/* ************************************ */
 
154
 
 
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));
 
158
  } else {
 
159
    /* MAC */
 
160
    return(findHostByMAC(theSerial.value.ethAddress, actualDeviceId));
 
161
  }
 
162
}
 
163
 
 
164
/* ************************************ */
 
165
 
 
166
HostTraffic* findHostByMAC(char* macAddr, u_int actualDeviceId) {
 
167
  HostTraffic *el;
 
168
  short dummyShort = 0;
 
169
  u_int idx = hashHost(NULL, macAddr, &dummyShort, &el, actualDeviceId);
 
170
 
 
171
  if(el != NULL)
 
172
    return(el); /* Found */
 
173
  else if(idx == FLAG_NO_PEER)
 
174
    return(NULL);
 
175
  else
 
176
    el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
177
 
 
178
  for(; el != NULL; el = el->next) {
 
179
    if((el->ethAddress[0] != '\0') && (!strncmp(el->ethAddress, macAddr, LEN_ETHERNET_ADDRESS)))
 
180
      return(el);
 
181
  }
 
182
 
 
183
  return(NULL);
 
184
}
 
185
 
 
186
/* *****************************************************/
 
187
 
 
188
#ifdef INET6
 
189
unsigned long in6_hash(struct in6_addr *addr) {
 
190
  return
 
191
    (addr->s6_addr[13]      ) | (addr->s6_addr[15] << 8) |
 
192
    (addr->s6_addr[14] << 16) | (addr->s6_addr[11] << 24);
 
193
 
 
194
}
 
195
#endif
 
196
 
 
197
/* *************************************** */
 
198
 
 
199
unsigned short computeIdx(HostAddr *srcAddr, HostAddr *dstAddr, int sport, int dport) {
 
200
 
 
201
  unsigned short idx;
 
202
  if (srcAddr->hostFamily != dstAddr->hostFamily)
 
203
    return -1;
 
204
  switch (srcAddr->hostFamily){
 
205
  case AF_INET:
 
206
    /*
 
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.
 
210
     *
 
211
     * Patch on the line below courtesy of
 
212
     * Paul Chapman <pchapman@fury.bio.dfo.ca>
 
213
     */
 
214
    idx = (u_int)(dstAddr->Ip4Address.s_addr+srcAddr->Ip4Address.s_addr+sport+dport) ;
 
215
    break;
 
216
#ifdef INET6
 
217
  case AF_INET6:
 
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);
 
222
    break;
 
223
#endif
 
224
  }
 
225
  return idx;
 
226
}
 
227
 
 
228
/* ******************************************** */
 
229
 
 
230
u_int16_t computeTransId(HostAddr *srcAddr, HostAddr *dstAddr, int sport, int dport) {
 
231
  u_int16_t transactionId;
 
232
  if (srcAddr->hostFamily != dstAddr->hostFamily)
 
233
    return -1;
 
234
  switch (srcAddr->hostFamily){
 
235
  case AF_INET:
 
236
    transactionId = (u_int16_t)(3*srcAddr->Ip4Address.s_addr+
 
237
                                dstAddr->Ip4Address.s_addr+5*dport+7*sport);
 
238
    break;
 
239
#ifdef INET6
 
240
  case AF_INET6:
 
241
    transactionId = (u_int16_t)(3*srcAddr->Ip6Address.s6_addr[0]+
 
242
                                dstAddr->Ip6Address.s6_addr[0]+5*dport+7*sport);
 
243
    break;
 
244
#endif
 
245
  }
 
246
  return transactionId;
 
247
}
 
248
 
 
249
/* ***************************** */
 
250
 
 
251
#ifdef INET6
 
252
int in6_isglobal(struct in6_addr *addr) {
 
253
  return (addr->s6_addr[0] & 0xe0) == 0x20;
 
254
}
 
255
#endif
 
256
 
 
257
/* ***************************** */
 
258
 
 
259
short addrcmp(HostAddr *addr1, HostAddr *addr2) {
 
260
 
 
261
  if(addr1 == NULL)
 
262
    if(addr2 == NULL)
 
263
      return 0;
 
264
    else
 
265
      return 1;
 
266
  else if(addr2 == NULL)
 
267
    return -1;
 
268
 
 
269
  if(addr1->hostFamily == 0)
 
270
    if(addr2->hostFamily == 0)
 
271
      return 0;
 
272
    else
 
273
      return 1;
 
274
  else if(addr2->hostFamily == 0)
 
275
    return -1;
 
276
 
 
277
  if(addr1->hostFamily != addr2->hostFamily)
 
278
    if(addr1->hostFamily > addr2->hostFamily)
 
279
      return 1;
 
280
    else
 
281
      return -1;
 
282
 
 
283
  switch (addr1->hostFamily){
 
284
  case AF_INET:
 
285
    if (addr1->Ip4Address.s_addr > addr2->Ip4Address.s_addr)
 
286
      return (1);
 
287
    else if (addr1->Ip4Address.s_addr < addr2->Ip4Address.s_addr)
 
288
      return (-1);
 
289
    else
 
290
      return (0);
 
291
    /*return (addr1->Ip4Address.s_addr != addr2->Ip4Address.s_addr);*/
 
292
 
 
293
#ifdef INET6
 
294
  case AF_INET6:
 
295
    if(memcmp(&addr1->Ip6Address,&addr2->Ip6Address,sizeof(struct in6_addr)) > 0)
 
296
      return (1);
 
297
    else if (memcmp(&addr1->Ip6Address,&addr2->Ip6Address,sizeof(struct in6_addr)) <0)
 
298
      return (-1);
 
299
    else
 
300
      return (0);
 
301
    break;
 
302
#endif
 
303
  default:
 
304
    return 1;
 
305
  }
 
306
}
 
307
 
 
308
/* ****************************************** */
 
309
 
 
310
HostAddr *addrcpy(HostAddr *dst, HostAddr *src) {
 
311
  dst->hostFamily = src->hostFamily;
 
312
  switch (src->hostFamily){
 
313
  case AF_INET:
 
314
    return memcpy(&dst->Ip4Address,&src->Ip4Address,sizeof(struct in_addr));
 
315
#ifdef INET6
 
316
  case AF_INET6:
 
317
    return memcpy(&dst->Ip6Address,&src->Ip6Address,sizeof(struct in6_addr));
 
318
#endif
 
319
 
 
320
  default:
 
321
    return NULL;
 
322
  }
 
323
}
 
324
 
 
325
/* ****************************************** */
 
326
 
 
327
int addrinit(HostAddr *addr) {
 
328
  addr->hostFamily = AF_INET;
 
329
  addr->Ip4Address.s_addr = 0;
 
330
  return(0);
 
331
}
 
332
 
 
333
/* ****************************************** */
 
334
 
 
335
unsigned short addrget(HostAddr *Haddr,void *addr, int *family , int *size) {
 
336
  struct in_addr v4addr;
 
337
 
 
338
  *family = Haddr->hostFamily;
 
339
  switch(Haddr->hostFamily){
 
340
  case AF_INET:
 
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);
 
344
    break;
 
345
#ifdef INET6
 
346
  case AF_INET6:
 
347
    memcpy((struct in6_addr *)addr,&Haddr->Ip6Address, sizeof(struct in6_addr));
 
348
    *size = sizeof(struct in6_addr);
 
349
    break;
 
350
#endif
 
351
  }
 
352
  return 1;
 
353
}
 
354
 
 
355
/* ****************************************** */
 
356
 
 
357
unsigned short addrput(int family, HostAddr *dst, void *src) {
 
358
  if (dst == NULL)
 
359
    return -1;
 
360
  dst->hostFamily = family;
 
361
  switch (family){
 
362
  case AF_INET:
 
363
    memcpy(&dst->Ip4Address, (struct in_addr *)src,sizeof(struct in_addr));
 
364
    break;
 
365
#ifdef INET6
 
366
  case AF_INET6:
 
367
    memcpy(&dst->Ip6Address, (struct in6_addr *)src, sizeof(struct in6_addr));
 
368
    break;
 
369
#endif
 
370
  }
 
371
  return(1);
 
372
}
 
373
 
 
374
/* ****************************************** */
 
375
 
 
376
unsigned short addrnull(HostAddr *addr) {
 
377
  switch(addr->hostFamily){
 
378
  case AF_INET:
 
379
    return (addr->Ip4Address.s_addr == 0x0);
 
380
#ifdef INET6
 
381
  case AF_INET6:
 
382
    return (addr->Ip6Address.s6_addr[0] == 0x0);
 
383
#endif
 
384
  default:
 
385
    return(1);
 
386
  }
 
387
}
 
388
 
 
389
/* ****************************************** */
 
390
 
 
391
unsigned short addrfull(HostAddr *addr) {
 
392
  switch(addr->hostFamily){
 
393
  case AF_INET:
 
394
    return (addr->Ip4Address.s_addr == 0xffffffff);
 
395
#ifdef INET6
 
396
  case AF_INET6:
 
397
    return(0);
 
398
#endif
 
399
  default: return 0;
 
400
  }
 
401
}
 
402
 
 
403
/* ****************************************** */
 
404
 
 
405
#ifdef INET6
 
406
unsigned short prefixlookup(struct in6_addr *addr, NtopIfaceAddr *addrs, int size) {
 
407
  int found = 0;
 
408
  NtopIfaceAddr *it;
 
409
 
 
410
  for (it = addrs ; it != NULL; it = it->next){
 
411
    if (size == 0)
 
412
      size = it->af.inet6.prefixlen / 8;
 
413
#if DEBUG
 
414
    {
 
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);
 
419
    }
 
420
#endif
 
421
    if (memcmp(&it->af.inet6.ifAddr,addr,size) == 0){
 
422
      found = 1;
 
423
      break;
 
424
    }
 
425
  }
 
426
 
 
427
  return found;
 
428
}
 
429
#endif
 
430
 
 
431
/* ****************************************** */
 
432
 
 
433
#ifdef INET6
 
434
unsigned short addrlookup(struct in6_addr *addr,  NtopIfaceAddr *addrs) {
 
435
  return (prefixlookup(addr,addrs, sizeof(struct in6_addr)));
 
436
}
 
437
#endif
 
438
 
 
439
/* ****************************************** */
 
440
 
 
441
#ifdef INET6
 
442
NtopIfaceAddr *getLocalHostAddressv6(NtopIfaceAddr *addrs, char* device) {
 
443
  struct iface_handler        *ih;
 
444
  struct iface_if             *ii;
 
445
  struct iface_addr           *ia;
 
446
  NtopIfaceAddr               *tmp = NULL;
 
447
  int count, addr_pos;
 
448
 
 
449
  if(!(ih = iface_new()))
 
450
    return NULL;
 
451
 
 
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));
 
458
        addr_pos = 0;
 
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];
 
469
            addr_pos++;
 
470
          }
 
471
        }
 
472
      }
 
473
 
 
474
  if(tmp != NULL) tmp->next = NULL;
 
475
  iface_destroy(ih);
 
476
#ifdef DEBUG
 
477
  traceEvent(CONST_TRACE_INFO, "DEBUG: Local address is: %s", intop(hostAddress));
 
478
#endif
 
479
  return addrs;
 
480
 
 
481
}
 
482
#endif
 
483
 
 
484
/*******************************************/
 
485
/*
 
486
 * Copy arg vector into a new buffer, concatenating arguments with spaces.
 
487
 */
 
488
char* copy_argv(register char **argv) {
 
489
  register char **p;
 
490
  register u_int len = 0;
 
491
  char *buf;
 
492
  char *src, *dst;
 
493
 
 
494
  p = argv;
 
495
  if(*p == 0)
 
496
    return 0;
 
497
 
 
498
  while (*p)
 
499
    len += strlen(*p++) + 1;
 
500
 
 
501
  buf = (char*)malloc(len);
 
502
  if(buf == NULL) {
 
503
    traceEvent(CONST_TRACE_FATALERROR, "Insufficient memory for copy_argv");
 
504
    exit(-1);
 
505
  }
 
506
 
 
507
  p = argv;
 
508
  dst = buf;
 
509
  while ((src = *p++) != NULL) {
 
510
    while ((*dst++ = *src++) != '\0')
 
511
      ;
 
512
    dst[-1] = ' ';
 
513
  }
 
514
  dst[-1] = '\0';
 
515
 
 
516
  return buf;
 
517
}
 
518
 
 
519
/**************************************/
 
520
 
 
521
#ifdef INET6
 
522
unsigned short isLinkLocalAddress(struct in6_addr *addr) {
 
523
  int i;
 
524
 
 
525
  if(addr == NULL)
 
526
    return 1;
 
527
  else if(addr->s6_addr == 0x0)
 
528
    return 0; /* IP-less myGlobals.device (is it trying to boot via DHCP/BOOTP ?) */
 
529
  else {
 
530
    for(i=0; i<myGlobals.numDevices; i++)
 
531
      if(IN6_IS_ADDR_LINKLOCAL(addr)) {
 
532
#ifdef DEBUG
 
533
        traceEvent(CONST_TRACE_INFO, "DEBUG: %s is a linklocal address", intop(addr));
 
534
#endif
 
535
        return 1;
 
536
      }
 
537
    return 0;
 
538
  }
 
539
}
 
540
#endif
 
541
 
 
542
/*******************************************/
 
543
 
 
544
#ifdef INET6
 
545
unsigned short in6_isMulticastAddress(struct in6_addr *addr) {
 
546
  if(IN6_IS_ADDR_MULTICAST(addr)) {
 
547
#ifdef DEBUG
 
548
    traceEvent(CONST_TRACE_INFO, "DEBUG: %s is multicast [%X/%X]",
 
549
               intop(addr));
 
550
#endif
 
551
    return 1;
 
552
  } else
 
553
    return 0;
 
554
}
 
555
#endif
 
556
 
 
557
/*******************************************/
 
558
 
 
559
#ifdef INET6
 
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);
 
564
    return(0);
 
565
  }
 
566
 
 
567
  if(addrlookup(addr,myGlobals.device[deviceId].v6Addrs) == 1) {
 
568
#ifdef ADDRESS_DEBUG
 
569
    traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intop(addr));
 
570
#endif
 
571
    return 1;
 
572
  }
 
573
 
 
574
  if(myGlobals.trackOnlyLocalHosts)
 
575
    return(0);
 
576
 
 
577
#ifdef DEBUG
 
578
  traceEvent(CONST_TRACE_INFO, "DEBUG: %s is %s", intop(addr));
 
579
#endif
 
580
  /* Link Local Addresses are local */
 
581
  return(isLinkLocalAddress(addr));
 
582
}
 
583
 
 
584
/* ******************************************* */
 
585
 
 
586
unsigned short in6_isPrivateAddress(struct in6_addr *addr) {
 
587
  /* IPv6 have private addresses ?*/
 
588
  return(0);
 
589
}
 
590
#endif
 
591
 
 
592
/* ********************************* */
 
593
 
 
594
unsigned short in_isBroadcastAddress(struct in_addr *addr) {
 
595
  int i;
 
596
 
 
597
  if(addr == NULL)
 
598
    return 1;
 
599
  else if(addr->s_addr == 0x0)
 
600
    return 0; /* IP-less myGlobals.device (is it trying to boot via DHCP/BOOTP ?) */
 
601
  else {
 
602
    for(i=0; i<myGlobals.numDevices; i++) {
 
603
      if(!myGlobals.device[i].virtualDevice) {
 
604
        if(myGlobals.device[i].netmask.s_addr == 0xFFFFFFFF) /* PPP */
 
605
          return 0;
 
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 */
 
609
                ) {
 
610
#ifdef DEBUG
 
611
          traceEvent(CONST_TRACE_INFO, "DEBUG: %s is a broadcast address", intoa(*addr));
 
612
#endif
 
613
          return 1;
 
614
        }
 
615
      }
 
616
    }
 
617
 
 
618
    return(in_isPseudoBroadcastAddress(addr));
 
619
  }
 
620
}
 
621
 
 
622
/* ********************************* */
 
623
 
 
624
unsigned short in_isMulticastAddress(struct in_addr *addr) {
 
625
  if((addr->s_addr & CONST_MULTICAST_MASK) == CONST_MULTICAST_MASK) {
 
626
#ifdef DEBUG
 
627
    traceEvent(CONST_TRACE_INFO, "DEBUG: %s is multicast [%X/%X]",
 
628
               intoa(*addr),
 
629
               ((unsigned long)(addr->s_addr) & CONST_MULTICAST_MASK),
 
630
               CONST_MULTICAST_MASK
 
631
               );
 
632
#endif
 
633
    return 1;
 
634
  } else
 
635
    return 0;
 
636
}
 
637
 
 
638
/* ********************************* */
 
639
 
 
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);
 
644
    return(0);
 
645
  }
 
646
 
 
647
#ifdef ADDRESS_DEBUG
 
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));
 
651
#endif
 
652
 
 
653
  if(addr == NULL) return(0);
 
654
 
 
655
  if(!myGlobals.mergeInterfaces) {
 
656
    if((addr->s_addr & myGlobals.device[deviceId].netmask.s_addr) == myGlobals.device[deviceId].network.s_addr) {
 
657
#ifdef ADDRESS_DEBUG
 
658
      traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intoa(*addr));
 
659
#endif
 
660
      return 1;
 
661
    }
 
662
  } else {
 
663
    int i;
 
664
 
 
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) {
 
667
#ifdef ADDRESS_DEBUG
 
668
        traceEvent(CONST_TRACE_INFO, "ADDRESS_DEBUG: %s is local", intoa(*addr));
 
669
#endif
 
670
        return 1;
 
671
      }
 
672
  }
 
673
 
 
674
  if(myGlobals.trackOnlyLocalHosts)
 
675
    return(0);
 
676
 
 
677
#ifdef DEBUG
 
678
  traceEvent(CONST_TRACE_INFO, "DEBUG: %s is %s", intoa(*addr),
 
679
             isBroadcastAddress(addr) ? "pseudolocal" : "remote");
 
680
#endif
 
681
  /* Broadcast is considered a local address */
 
682
  return(in_isBroadcastAddress(addr));
 
683
}
 
684
 
 
685
/* ********************************* */
 
686
 
 
687
unsigned short in_isPrivateAddress(struct in_addr *addr) {
 
688
  /* See http://www.isi.edu/in-notes/rfc1918.txt */
 
689
 
 
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 */
 
694
     )
 
695
    return(1);
 
696
  else
 
697
    return(0);
 
698
}
 
699
 
 
700
/***************************************/
 
701
 
 
702
unsigned short isBroadcastAddress(HostAddr *addr){
 
703
  switch(addr->hostFamily){
 
704
  case AF_INET:
 
705
    return (in_isBroadcastAddress(&addr->Ip4Address));
 
706
#ifdef INET6
 
707
  case AF_INET6:
 
708
    return (isLinkLocalAddress(&addr->Ip6Address));
 
709
#endif
 
710
  default: return(0);
 
711
  }
 
712
}
 
713
 
 
714
/* ******************************************** */
 
715
 
 
716
unsigned short isMulticastAddress(HostAddr *addr){
 
717
  switch(addr->hostFamily){
 
718
  case AF_INET:
 
719
    return (in_isMulticastAddress(&addr->Ip4Address));
 
720
#ifdef INET6
 
721
  case AF_INET6:
 
722
    return (in6_isMulticastAddress(&addr->Ip6Address));
 
723
#endif
 
724
  default: return(0);
 
725
  }
 
726
}
 
727
 
 
728
/* ************************************************* */
 
729
 
 
730
unsigned short isLocalAddress(HostAddr *addr, u_int deviceId) {
 
731
  switch(addr->hostFamily){
 
732
  case AF_INET:
 
733
    return (in_isLocalAddress(&addr->Ip4Address, deviceId));
 
734
#ifdef INET6
 
735
  case AF_INET6:
 
736
    return (in6_isLocalAddress(&addr->Ip6Address, deviceId));
 
737
#endif
 
738
  default: return(0);
 
739
  }
 
740
}
 
741
 
 
742
/* ************************************************** */
 
743
 
 
744
unsigned short isPrivateAddress(HostAddr *addr) {
 
745
  switch(addr->hostFamily){
 
746
  case AF_INET:
 
747
    return (in_isPrivateAddress(&addr->Ip4Address));
 
748
#ifdef INET6
 
749
  case AF_INET6:
 
750
    return (in6_isPrivateAddress(&addr->Ip6Address));
 
751
#endif
 
752
  default: return(0);
 
753
  }
 
754
}
 
755
 
 
756
 
 
757
/* **********************************************
 
758
 *
 
759
 * Description:
 
760
 *
 
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:
 
768
 *
 
769
 *     1111 1000 -> valid
 
770
 *     1110 1000 -> invalid
 
771
 *
 
772
 * Return values:
 
773
 *     0 - 8 (number of subsequent
 
774
 *            bits set to 1)
 
775
 *    -1     (CONST_INVALIDNETMASK)
 
776
 *
 
777
 *
 
778
 * Courtesy of Antonello Maiorca <marty@tai.it>
 
779
 *
 
780
 *********************************************** */
 
781
 
 
782
static int int2bits(int number) {
 
783
  int bits = 8;
 
784
  int test;
 
785
 
 
786
  if((number > 255) || (number < 0))
 
787
    {
 
788
#ifdef DEBUG
 
789
      traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, CONST_INVALIDNETMASK);
 
790
#endif
 
791
      return(CONST_INVALIDNETMASK);
 
792
    }
 
793
  else
 
794
    {
 
795
      test = ~number & 0xff;
 
796
      while (test & 0x1)
 
797
        {
 
798
          bits --;
 
799
          test = test >> 1;
 
800
        }
 
801
      if(number != ((~(0xff >> bits)) & 0xff))
 
802
        {
 
803
#ifdef DEBUG
 
804
          traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, CONST_INVALIDNETMASK);
 
805
#endif
 
806
          return(CONST_INVALIDNETMASK);
 
807
        }
 
808
      else
 
809
        {
 
810
#ifdef DEBUG
 
811
          traceEvent(CONST_TRACE_INFO, "DEBUG: int2bits (%3d) = %d", number, bits);
 
812
#endif
 
813
          return(bits);
 
814
        }
 
815
    }
 
816
}
 
817
 
 
818
/* ***********************************************
 
819
 *
 
820
 * Description:
 
821
 *
 
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:
 
831
 *
 
832
 *     1111 1000 -> valid
 
833
 *     1110 1000 -> invalid
 
834
 *
 
835
 * Return values:
 
836
 *     0 - 32 (number of subsequent
 
837
 *             bits set to 1)
 
838
 *    -1      (CONST_INVALIDNETMASK)
 
839
 *
 
840
 *
 
841
 * Courtesy of Antonello Maiorca <marty@tai.it>
 
842
 *
 
843
 *********************************************** */
 
844
 
 
845
int dotted2bits(char *mask) {
 
846
  int           fields[4];
 
847
  int           fields_num, field_bits;
 
848
  int           bits = 0;
 
849
  int           i;
 
850
 
 
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))
 
854
    {
 
855
#ifdef DEBUG
 
856
      traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%s) = %d", mask, fields[0]);
 
857
#endif
 
858
      return(fields[0]);
 
859
    }
 
860
  for (i=0; i < fields_num; i++)
 
861
    {
 
862
      /* We are in a dotted quad notation. */
 
863
      field_bits = int2bits (fields[i]);
 
864
      switch (field_bits)
 
865
        {
 
866
        case CONST_INVALIDNETMASK:
 
867
          return(CONST_INVALIDNETMASK);
 
868
 
 
869
        case 0:
 
870
          /* whenever a 0 bits field is reached there are no more */
 
871
          /* fields to scan                                       */
 
872
#ifdef DEBUG
 
873
          traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%15s) = %d", mask, bits);
 
874
#endif
 
875
          /* In this case we are in a bits (not dotted quad) notation */
 
876
          return(bits /* fields[0] - L.Deri 08/2001 */);
 
877
 
 
878
        default:
 
879
          bits += field_bits;
 
880
        }
 
881
    }
 
882
#ifdef DEBUG
 
883
  traceEvent(CONST_TRACE_INFO, "DEBUG: dotted2bits (%15s) = %d", mask, bits);
 
884
#endif
 
885
  return(bits);
 
886
}
 
887
 
 
888
/* ********************************* */
 
889
 
 
890
/* Example: "131.114.0.0/16,193.43.104.0/255.255.255.0" */
 
891
 
 
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;
 
897
 
 
898
  if((addresses == NULL) || (addresses[0] == '\0'))
 
899
    return;
 
900
 
 
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",
 
906
             addresses);
 
907
 
 
908
  memset(localAddresses, 0, localAddressesLen);
 
909
 
 
910
  address = strtok_r(addresses, ",", &strtokState);
 
911
 
 
912
  while(address != NULL) {
 
913
    char *mask = strchr(address, '/');
 
914
 
 
915
    if(mask == NULL) {
 
916
      if (flagWhat == CONST_HANDLEADDRESSLISTS_MAIN)
 
917
        traceEvent(CONST_TRACE_WARNING, "-m: Empty mask '%s' - ignoring entry", address);
 
918
    } else {
 
919
      u_int32_t network, networkMask, broadcast;
 
920
      int bits, a, b, c, d;
 
921
 
 
922
      mask[0] = '\0';
 
923
      mask++;
 
924
      bits = dotted2bits (mask);
 
925
 
 
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",
 
931
                   address);
 
932
        address = strtok_r(NULL, ",", &strtokState);
 
933
        continue;
 
934
      }
 
935
 
 
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",
 
942
                   mask);
 
943
        address = strtok_r(NULL, ",", &strtokState);
 
944
        continue;
 
945
      }
 
946
 
 
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
 
951
      */
 
952
      if (bits == 32) {
 
953
        networkMask = 0xffffffff;
 
954
      } else {
 
955
        networkMask = 0xffffffff >> bits;
 
956
        networkMask = ~networkMask;
 
957
      }
 
958
 
 
959
#ifdef DEBUG
 
960
      traceEvent(CONST_TRACE_INFO, "DEBUG: Nw=%08X - Mask: %08X [%08X]",
 
961
                 network, networkMask, (network & networkMask));
 
962
#endif
 
963
 
 
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",
 
971
                   a, b, c, d, bits);
 
972
 
 
973
        /* correcting network numbers as specified in the netmask */
 
974
        network &= networkMask;
 
975
 
 
976
        a = (int) ((network >> 24) & 0xff);
 
977
        b = (int) ((network >> 16) & 0xff);
 
978
        c = (int) ((network >>  8) & 0xff);
 
979
        d = (int) ((network >>  0) & 0xff);
 
980
 
 
981
        traceEvent(CONST_TRACE_NOISY, "Assuming %d.%d.%d.%d/%d [0x%08x/0x%08x]",
 
982
                   a, b, c, d, bits, network, networkMask);
 
983
      }
 
984
#ifdef DEBUG
 
985
      traceEvent(CONST_TRACE_INFO, "DEBUG: %d.%d.%d.%d/%d [0x%08x/0x%08x]",
 
986
                 a, b, c, d, bits, network, networkMask);
 
987
#endif
 
988
 
 
989
      broadcast = network | (~networkMask);
 
990
 
 
991
#ifdef DEBUG
 
992
      a = (int) ((broadcast >> 24) & 0xff);
 
993
      b = (int) ((broadcast >> 16) & 0xff);
 
994
      c = (int) ((broadcast >>  8) & 0xff);
 
995
      d = (int) ((broadcast >>  0) & 0xff);
 
996
 
 
997
      traceEvent(CONST_TRACE_INFO, "DEBUG: Broadcast: [net=0x%08x] [broadcast=%d.%d.%d.%d]",
 
998
                 network, a, b, c, d);
 
999
#endif
 
1000
 
 
1001
      if((*numNetworks) < MAX_NUM_NETWORKS) {
 
1002
        int found = 0;
 
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.
 
1006
         */
 
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);
 
1015
 
 
1016
              traceEvent(CONST_TRACE_INFO,
 
1017
                         "-m: Discarded unnecessary parameter %d.%d.%d.%d/%d - this is the local network",
 
1018
                         a, b, c, d, bits);
 
1019
              found = 1;
 
1020
            }
 
1021
          }
 
1022
        }
 
1023
 
 
1024
        if(found == 0) {
 
1025
          theNetworks[(*numNetworks)][CONST_NETWORK_ENTRY]   = network;
 
1026
          theNetworks[(*numNetworks)][CONST_NETMASK_ENTRY]   = networkMask;
 
1027
          theNetworks[(*numNetworks)][CONST_BROADCAST_ENTRY] = broadcast;
 
1028
 
 
1029
          a = (int) ((network >> 24) & 0xff);
 
1030
          b = (int) ((network >> 16) & 0xff);
 
1031
          c = (int) ((network >>  8) & 0xff);
 
1032
          d = (int) ((network >>  0) & 0xff);
 
1033
 
 
1034
          if ((laBufferUsed = snprintf(&localAddresses[laBufferPosition],
 
1035
                                       localAddressesLen,
 
1036
                                       "%s%d.%d.%d.%d/%d",
 
1037
                                       (*numNetworks) == 0 ? "" : ", ",
 
1038
                                       a, b, c, d,
 
1039
                                       bits)) < 0)
 
1040
            BufferTooShort();
 
1041
 
 
1042
          laBufferPosition  += laBufferUsed;
 
1043
          localAddressesLen -= laBufferUsed;
 
1044
 
 
1045
          (*numNetworks)++;
 
1046
 
 
1047
        }
 
1048
      } else {
 
1049
        a = (int) ((network >> 24) & 0xff);
 
1050
        b = (int) ((network >> 16) & 0xff);
 
1051
        c = (int) ((network >>  8) & 0xff);
 
1052
        d = (int) ((network >>  0) & 0xff);
 
1053
 
 
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",
 
1058
                   a, b, c, d, bits,
 
1059
                   MAX_NUM_NETWORKS);
 
1060
      }
 
1061
    }
 
1062
 
 
1063
    address = strtok_r(NULL, ",", &strtokState);
 
1064
  }
 
1065
}
 
1066
 
 
1067
/* ********************************* */
 
1068
 
 
1069
void handleLocalAddresses(char* addresses) {
 
1070
  char localAddresses[1024];
 
1071
 
 
1072
  localAddresses[0] = '\0';
 
1073
 
 
1074
  handleAddressLists(addresses, myGlobals.localNetworks, &myGlobals.numLocalNetworks,
 
1075
                     localAddresses, sizeof(localAddresses), CONST_HANDLEADDRESSLISTS_MAIN);
 
1076
 
 
1077
  /* Not used anymore */
 
1078
  if(myGlobals.localAddresses != NULL) free(myGlobals.localAddresses);
 
1079
  
 
1080
  if(localAddresses[0]  != '\0')
 
1081
    myGlobals.localAddresses = strdup(localAddresses);
 
1082
}
 
1083
 
 
1084
/* ********************************* */
 
1085
 
 
1086
#ifdef INET6
 
1087
unsigned short in6_pseudoLocalAddress(struct in6_addr *addr) {
 
1088
  int i;
 
1089
 
 
1090
  for(i=0; i<myGlobals.numDevices; i++) {
 
1091
    if (prefixlookup(addr,myGlobals.device[i].v6Addrs,0) == 1)
 
1092
      return (1);
 
1093
 
 
1094
  }
 
1095
  return(0);
 
1096
}
 
1097
#endif
 
1098
 
 
1099
unsigned short __pseudoLocalAddress(struct in_addr *addr,
 
1100
                                    u_int32_t theNetworks[MAX_NUM_NETWORKS][3],
 
1101
                                    u_short numNetworks) {
 
1102
  int i;
 
1103
 
 
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;
 
1108
 
 
1109
    addr1.s_addr = theNetworks[i][CONST_NETWORK_ENTRY];
 
1110
    addr2.s_addr = theNetworks[i][CONST_NETMASK_ENTRY];
 
1111
 
 
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)));
 
1116
#endif
 
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));
 
1120
#endif
 
1121
      return 1;
 
1122
    } else {
 
1123
#ifdef ADDRESS_DEBUG
 
1124
      traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is NOT pseudolocal", intoa(*addr));
 
1125
#endif
 
1126
    }
 
1127
  }
 
1128
 
 
1129
  return(0);
 
1130
}
 
1131
 
 
1132
/* ********************************* */
 
1133
 
 
1134
unsigned short in_pseudoLocalAddress(struct in_addr *addr) {
 
1135
  return(__pseudoLocalAddress(addr, myGlobals.localNetworks, myGlobals.numLocalNetworks));
 
1136
}
 
1137
 
 
1138
/* ********************************* */
 
1139
 
 
1140
#ifdef INET6
 
1141
unsigned short in6_deviceLocalAddress(struct in6_addr *addr, u_int deviceId) {
 
1142
  int rc;
 
1143
 
 
1144
  if(addrlookup(addr,myGlobals.device[deviceId].v6Addrs))
 
1145
    rc = 1;
 
1146
  else
 
1147
    rc = 0;
 
1148
 
 
1149
  return(rc);
 
1150
}
 
1151
#endif
 
1152
 
 
1153
/* ********************************* */
 
1154
 
 
1155
unsigned short in_deviceLocalAddress(struct in_addr *addr, u_int deviceId) {
 
1156
  int rc;
 
1157
 
 
1158
  if((addr->s_addr & myGlobals.device[deviceId].netmask.s_addr) == myGlobals.device[deviceId].network.s_addr)
 
1159
    rc = 1;
 
1160
  else
 
1161
    rc = 0;
 
1162
 
 
1163
#if DEBUG
 
1164
  {
 
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);
 
1169
  }
 
1170
#endif
 
1171
 
 
1172
  return(rc);
 
1173
}
 
1174
 
 
1175
/* ********************************* */
 
1176
 
 
1177
#ifdef INET6
 
1178
unsigned short in6_isPseudoLocalAddress(struct in6_addr *addr, u_int deviceId) {
 
1179
  int i;
 
1180
 
 
1181
  i = in6_isLocalAddress(addr, deviceId);
 
1182
 
 
1183
  if(i == 1) {
 
1184
#ifdef ADDRESS_DEBUG
 
1185
    traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is local", intop(addr));
 
1186
#endif
 
1187
 
 
1188
    return 1; /* This is a real local address */
 
1189
  }
 
1190
 
 
1191
  if(in6_pseudoLocalAddress(addr))
 
1192
    return 1;
 
1193
 
 
1194
  /*
 
1195
    We don't check for broadcast as this check has been
 
1196
    performed already by isLocalAddress() just called
 
1197
  */
 
1198
 
 
1199
#ifdef ADDRESS_DEBUG
 
1200
  traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is remote", intop(addr));
 
1201
#endif
 
1202
 
 
1203
  return(0);
 
1204
}
 
1205
#endif
 
1206
 
 
1207
/* ******************************************** */
 
1208
 
 
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) {
 
1212
  int i;
 
1213
 
 
1214
  i = in_isLocalAddress(addr, deviceId);
 
1215
 
 
1216
  if(i == 1) {
 
1217
#ifdef ADDRESS_DEBUG
 
1218
    traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s is local", intoa(*addr));
 
1219
#endif
 
1220
 
 
1221
    return 1; /* This is a real local address */
 
1222
  }
 
1223
 
 
1224
  if(in_pseudoLocalAddress(addr))
 
1225
    return 1;
 
1226
 
 
1227
  /*
 
1228
    We don't check for broadcast as this check has been
 
1229
    performed already by isLocalAddress() just called
 
1230
  */
 
1231
 
 
1232
#ifdef ADDRESS_DEBUG
 
1233
  traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %s [deviceId=%d] is remote",
 
1234
             intoa(*addr), deviceId);
 
1235
#endif
 
1236
 
 
1237
  return(0);
 
1238
}
 
1239
 
 
1240
/* ********************************* */
 
1241
 
 
1242
/* This function returns true when an address is the broadcast
 
1243
   for the specified (-m flag subnets */
 
1244
 
 
1245
unsigned short in_isPseudoBroadcastAddress(struct in_addr *addr) {
 
1246
  int i;
 
1247
 
 
1248
#ifdef ADDRESS_DEBUG
 
1249
  traceEvent(CONST_TRACE_WARNING, "DEBUG: Checking %8X (pseudo broadcast)", addr->s_addr);
 
1250
#endif
 
1251
 
 
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);
 
1256
#endif
 
1257
      return 1;
 
1258
    }
 
1259
#ifdef ADDRESS_DEBUG
 
1260
    else
 
1261
      traceEvent(CONST_TRACE_WARNING, "ADDRESS_DEBUG: %8X is NOT pseudo broadcast", addr->s_addr);
 
1262
#endif
 
1263
  }
 
1264
 
 
1265
  return(0);
 
1266
}
 
1267
 
 
1268
/*************************************/
 
1269
 
 
1270
unsigned short deviceLocalAddress(HostAddr *addr, u_int deviceId) {
 
1271
  switch(addr->hostFamily){
 
1272
  case AF_INET:
 
1273
    return (in_deviceLocalAddress(&addr->Ip4Address, deviceId));
 
1274
#ifdef INET6
 
1275
  case AF_INET6:
 
1276
    return (in6_deviceLocalAddress(&addr->Ip6Address, deviceId));
 
1277
#endif
 
1278
  default: return(0);
 
1279
  }
 
1280
}
 
1281
 
 
1282
/* ********************************* */
 
1283
 
 
1284
unsigned short isPseudoLocalAddress(HostAddr *addr, u_int deviceId) {
 
1285
  switch(addr->hostFamily){
 
1286
  case AF_INET:
 
1287
    return (in_isPseudoLocalAddress(&addr->Ip4Address, deviceId));
 
1288
#ifdef INET6
 
1289
  case AF_INET6:
 
1290
    return (in6_isPseudoLocalAddress(&addr->Ip6Address, deviceId));
 
1291
#endif
 
1292
  default: return(0);
 
1293
  }
 
1294
}
 
1295
 
 
1296
/* ********************************* */
 
1297
 
 
1298
unsigned short isPseudoBroadcastAddress(HostAddr *addr) {
 
1299
  switch(addr->hostFamily){
 
1300
  case AF_INET:
 
1301
    return (in_isPseudoBroadcastAddress(&addr->Ip4Address));
 
1302
#ifdef INET6
 
1303
  case AF_INET6:
 
1304
    return 0;
 
1305
#endif
 
1306
  default: return(0);
 
1307
  }
 
1308
}
 
1309
 
 
1310
/* ********************************* */
 
1311
 
 
1312
unsigned short _pseudoLocalAddress(HostAddr *addr) {
 
1313
  switch(addr->hostFamily){
 
1314
  case AF_INET:
 
1315
    return (in_pseudoLocalAddress(&addr->Ip4Address));
 
1316
#ifdef INET6
 
1317
  case AF_INET6:
 
1318
    return (in6_pseudoLocalAddress(&addr->Ip6Address));
 
1319
#endif
 
1320
  default: return(0);
 
1321
  }
 
1322
}
 
1323
 
 
1324
/* ********************************* */
 
1325
 
 
1326
/*
 
1327
 * Returns the difference between gmt and local time in seconds.
 
1328
 * Use gmtime() and localtime() to keep things simple.
 
1329
 * [Borrowed from tcpdump]
 
1330
 */
 
1331
int32_t gmt2local(time_t t) {
 
1332
  int dt, dir;
 
1333
  struct tm *gmt, *myloc;
 
1334
  struct tm loc;
 
1335
 
 
1336
  if(t == 0)
 
1337
    t = time(NULL);
 
1338
 
 
1339
  gmt = gmtime(&t);
 
1340
  myloc = localtime_r(&t, &loc);
 
1341
 
 
1342
  dt = (myloc->tm_hour - gmt->tm_hour)*60*60+(myloc->tm_min - gmt->tm_min)*60;
 
1343
 
 
1344
  /*
 
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.
 
1348
   */
 
1349
  dir = myloc->tm_year - gmt->tm_year;
 
1350
  if(dir == 0)
 
1351
    dir = myloc->tm_yday - gmt->tm_yday;
 
1352
  dt += dir * 24 * 60 * 60;
 
1353
 
 
1354
  return(dt);
 
1355
}
 
1356
 
 
1357
/* ********************************* */
 
1358
 
 
1359
char *dotToSlash(char *name) {
 
1360
  /*
 
1361
   *  Convert a dotted quad ip address name a.b.c.d to a/b/c/d or a\b\c\d
 
1362
   */
 
1363
  char* localBuffer;
 
1364
  int i;
 
1365
 
 
1366
  localBuffer = strdup(name);
 
1367
 
 
1368
  for (i=0; i<strlen(localBuffer); i++) {
 
1369
    if((localBuffer[i] == '.') || (localBuffer[i] == ':'))
 
1370
#ifdef WIN32
 
1371
      localBuffer[i]='\\';
 
1372
#else
 
1373
    localBuffer[i]='/';
 
1374
#endif
 
1375
  }
 
1376
 
 
1377
  localBuffer[i]='\0';
 
1378
  return localBuffer;
 
1379
}
 
1380
 
 
1381
/* ********************************* */
 
1382
 
 
1383
/* Example: "flow1='host jake',flow2='dst host born2run'" */
 
1384
void handleFlowsSpecs(void) {
 
1385
  FILE *fd;
 
1386
  char *flow, *buffer=NULL, *strtokState, *flows;
 
1387
 
 
1388
  flows = myGlobals.flowSpecs;
 
1389
 
 
1390
  if((!flows) || (!flows[0]))
 
1391
    return;
 
1392
 
 
1393
  fd = fopen(flows, "rb");
 
1394
 
 
1395
  if(fd == NULL)
 
1396
    flow = strtok_r(flows, ",", &strtokState);
 
1397
  else {
 
1398
    struct stat buf;
 
1399
    int len, i;
 
1400
 
 
1401
    if(stat(flows, &buf) != 0) {
 
1402
      fclose(fd);
 
1403
      traceEvent(CONST_TRACE_INFO, "Error while stat() of %s", flows);
 
1404
 
 
1405
      /* Not used anymore */
 
1406
      free(myGlobals.flowSpecs);
 
1407
      myGlobals.flowSpecs = strdup("Error reading file");
 
1408
      return;
 
1409
    }
 
1410
 
 
1411
    buffer = (char*)malloc(buf.st_size+8) /* just to be safe */;
 
1412
 
 
1413
    for(i=0;i<buf.st_size;) {
 
1414
      len = fread(&buffer[i], sizeof(char), buf.st_size-i, fd);
 
1415
      if(len <= 0) break;
 
1416
      i += len;
 
1417
    }
 
1418
 
 
1419
    fclose(fd);
 
1420
 
 
1421
    /* remove trailing carriage return */
 
1422
    if(buffer[strlen(buffer)-1] == '\n')
 
1423
      buffer[strlen(buffer)-1] = 0;
 
1424
 
 
1425
    flow = strtok_r(buffer, ",", &strtokState);
 
1426
  }
 
1427
 
 
1428
  while(flow != NULL) {
 
1429
    char *flowSpec = strchr(flow, '=');
 
1430
 
 
1431
    if(flowSpec == NULL)
 
1432
      traceEvent(CONST_TRACE_INFO, "Missing flow spec '%s'. It has been ignored.", flow);
 
1433
    else {
 
1434
      struct bpf_program fcode;
 
1435
      int rc, len;
 
1436
      char *flowName = flow;
 
1437
 
 
1438
      flowSpec[0] = '\0';
 
1439
      flowSpec++;
 
1440
      /* flowSpec should now point to 'host jake' */
 
1441
      len = strlen(flowSpec);
 
1442
 
 
1443
      if((len <= 2)
 
1444
         || (flowSpec[0] != '\'')
 
1445
         || (flowSpec[len-1] != '\''))
 
1446
        traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (missing \'). "
 
1447
                   "It has been ignored.", flowSpec);
 
1448
      else {
 
1449
        flowSpec[len-1] = '\0';
 
1450
        flowSpec++;
 
1451
 
 
1452
        traceEvent(CONST_TRACE_NOISY, "Compiling flow specification '%s'", flowSpec);
 
1453
 
 
1454
        rc = pcap_compile(myGlobals.device[0].pcapPtr, &fcode, flowSpec, 1, myGlobals.device[0].netmask.s_addr);
 
1455
 
 
1456
        if(rc < 0)
 
1457
          traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (syntax error). "
 
1458
                     "It has been ignored.", flowSpec);
 
1459
        else {
 
1460
          FlowFilterList *newFlow;
 
1461
 
 
1462
#ifdef HAVE_PCAP_FREECODE
 
1463
          pcap_freecode(&fcode);
 
1464
#endif
 
1465
          newFlow = (FlowFilterList*)calloc(1, sizeof(FlowFilterList));
 
1466
 
 
1467
          if(newFlow == NULL) {
 
1468
            traceEvent(CONST_TRACE_INFO, "Fatal error: not enough memory. Bye!");
 
1469
            if(buffer != NULL) free(buffer);
 
1470
            exit(-1);
 
1471
          } else {
 
1472
            int i;
 
1473
 
 
1474
            newFlow->fcode = (struct bpf_program*)calloc(myGlobals.numDevices, sizeof(struct bpf_program));
 
1475
 
 
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);
 
1479
 
 
1480
              if(rc < 0) {
 
1481
                traceEvent(CONST_TRACE_WARNING, "Wrong flow specification \"%s\" (syntax error). "
 
1482
                           "It has been ignored.", flowSpec);
 
1483
                free(newFlow);
 
1484
 
 
1485
                /* Not used anymore */
 
1486
                free(myGlobals.flowSpecs);
 
1487
                myGlobals.flowSpecs = strdup("Error, wrong flow specification");
 
1488
                return;
 
1489
              }
 
1490
            }
 
1491
 
 
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;
 
1497
          }
 
1498
        }
 
1499
      }
 
1500
    }
 
1501
 
 
1502
    flow = strtok_r(NULL, ",", &strtokState);
 
1503
  }
 
1504
 
 
1505
  if(buffer != NULL)
 
1506
    free(buffer);
 
1507
 
 
1508
}
 
1509
 
 
1510
/* ********************************* */
 
1511
 
 
1512
int getLocalHostAddress(struct in_addr *hostAddress, char* device) {
 
1513
  int rc = 0;
 
1514
#ifdef WIN32
 
1515
  hostAddress->s_addr = GetHostIPAddr();
 
1516
  return(0);
 
1517
#else
 
1518
  int fd;
 
1519
  struct sockaddr_in *sinAddr;
 
1520
  struct ifreq ifr;
 
1521
#ifdef DEBUG
 
1522
  int a, b, c, d;
 
1523
#endif
 
1524
 
 
1525
  fd = socket(AF_INET, SOCK_DGRAM, 0);
 
1526
  if(fd < 0) {
 
1527
    traceEvent(CONST_TRACE_INFO, "socket error: %d", errno);
 
1528
    return(-1);
 
1529
  }
 
1530
 
 
1531
  memset(&ifr, 0, sizeof(ifr));
 
1532
 
 
1533
#ifdef LINUX
 
1534
  /* XXX Work around Linux kernel bug */
 
1535
  ifr.ifr_addr.sa_family = AF_INET;
 
1536
#endif
 
1537
  strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
 
1538
  if(ioctl(fd, SIOCGIFADDR, (char*)&ifr) < 0) {
 
1539
#ifdef DEBUG
 
1540
    traceEvent(CONST_TRACE_INFO, "DEBUG: SIOCGIFADDR error: %s/errno=%d", device, errno);
 
1541
#endif
 
1542
    rc = -1;
 
1543
  } else {
 
1544
    sinAddr = (struct sockaddr_in *)&ifr.ifr_addr;
 
1545
 
 
1546
    if((hostAddress->s_addr = ntohl(sinAddr->sin_addr.s_addr)) == 0)
 
1547
      rc = -1;
 
1548
  }
 
1549
 
 
1550
#ifdef DEBUG
 
1551
  traceEvent(CONST_TRACE_INFO, "DEBUG: Local address is: %s", intoa(*hostAddress));
 
1552
#endif
 
1553
 
 
1554
  /* ******************************* */
 
1555
 
 
1556
#ifdef DEBUG
 
1557
  {
 
1558
    int numHosts;
 
1559
 
 
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;
 
1563
    } else
 
1564
      numHosts = 256; /* default C class */
 
1565
 
 
1566
    traceEvent(CONST_TRACE_INFO, "DEBUG: Num subnet hosts: %d", numHosts);
 
1567
  }
 
1568
#endif
 
1569
 
 
1570
  /* ******************************* */
 
1571
 
 
1572
  close(fd);
 
1573
#endif
 
1574
 
 
1575
  return(rc);
 
1576
}
 
1577
 
 
1578
/* ********************************* */
 
1579
 
 
1580
#ifndef WIN32
 
1581
#ifdef CFG_MULTITHREADED
 
1582
 
 
1583
/* *********** MULTITHREAD STUFF *********** */
 
1584
 
 
1585
int createThread(pthread_t *threadId,
 
1586
                 void *(*__start_routine) (void *),
 
1587
                 char* userParm) {
 
1588
  int rc;
 
1589
 
 
1590
  rc = pthread_create(threadId, NULL, __start_routine, userParm);
 
1591
 
 
1592
  if(rc != 0)
 
1593
    traceEvent(CONST_TRACE_NOISY, "createThread(0x%x), rc = %s(%d)",
 
1594
               threadId, strerror(rc), rc);
 
1595
  myGlobals.numThreads++;
 
1596
  return(rc);
 
1597
}
 
1598
 
 
1599
/* ************************************ */
 
1600
 
 
1601
int killThread(pthread_t *threadId) {
 
1602
  int rc;
 
1603
  rc = pthread_detach(*threadId);
 
1604
 
 
1605
  if(rc != 0)
 
1606
    traceEvent(CONST_TRACE_NOISY, "killThread(0x%x), rc = %s(%d)",
 
1607
               threadId, strerror(rc), rc);
 
1608
 
 
1609
  myGlobals.numThreads--;
 
1610
  return(rc);
 
1611
}
 
1612
 
 
1613
/* ************************************ */
 
1614
 
 
1615
int _createMutex(PthreadMutex *mutexId, char* fileName, int fileLine) {
 
1616
  int rc;
 
1617
 
 
1618
  if(!stateChangeMutexInitialized) {
 
1619
    pthread_mutex_init(&stateChangeMutex, NULL);
 
1620
    stateChangeMutexInitialized = 1;
 
1621
  }
 
1622
 
 
1623
  memset(mutexId, 0, sizeof(PthreadMutex));
 
1624
 
 
1625
  rc = pthread_mutex_init(&(mutexId->mutex), NULL);
 
1626
 
 
1627
  if (rc != 0) {
 
1628
    traceEvent(CONST_TRACE_ERROR,
 
1629
               "createMutex() call returned %d(%d) [%s:%d]",
 
1630
               rc, errno, fileName, fileLine);
 
1631
  } else {
 
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);
 
1636
#endif
 
1637
  }
 
1638
 
 
1639
  return(rc);
 
1640
}
 
1641
 
 
1642
/* ************************************ */
 
1643
 
 
1644
void _deleteMutex(PthreadMutex *mutexId, char* fileName, int fileLine) {
 
1645
  int rc;
 
1646
 
 
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);
 
1652
    return;
 
1653
  }
 
1654
 
 
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);
 
1660
    return;
 
1661
  }
 
1662
 
 
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);
 
1667
#endif
 
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);
 
1672
#endif
 
1673
 
 
1674
  memset(mutexId, 0, sizeof(PthreadMutex));
 
1675
}
 
1676
 
 
1677
/* ************************************ */
 
1678
 
 
1679
int _accessMutex(PthreadMutex *mutexId, char* where,
 
1680
                 char* fileName, int fileLine) {
 
1681
  int rc;
 
1682
  pid_t myPid;
 
1683
 
 
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);
 
1689
    return(-1);
 
1690
  }
 
1691
 
 
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);
 
1697
    return(-1);
 
1698
  }
 
1699
 
 
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!
 
1704
   */
 
1705
  traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: accessMutex() called '%s' [0x%X@%s:%d]",
 
1706
             where, (void*)&(mutexId->mutex), fileName, fileLine);
 
1707
#endif
 
1708
 
 
1709
  if(!myGlobals.disableMutexExtraInfo) {
 
1710
    myPid=getpid();
 
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);
 
1719
      }
 
1720
    }
 
1721
 
 
1722
    strcpy(mutexId->lockAttemptFile, fileName);
 
1723
    mutexId->lockAttemptLine=fileLine;
 
1724
    mutexId->lockAttemptPid=myPid;
 
1725
  }
 
1726
 
 
1727
  rc = pthread_mutex_lock(&(mutexId->mutex));
 
1728
 
 
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();
 
1735
  }
 
1736
 
 
1737
  if(rc != 0)
 
1738
    traceEvent(CONST_TRACE_ERROR, "accessMutex() call '%s' failed (rc=%d) [0x%X@%s:%d]",
 
1739
               where, rc, (void*)&(mutexId->mutex), fileName, fileLine);
 
1740
  else {
 
1741
 
 
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);
 
1745
#endif
 
1746
 
 
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;
 
1755
      }
 
1756
      if(where != NULL) {
 
1757
        strcpy(mutexId->where, where);
 
1758
      }
 
1759
    }
 
1760
  }
 
1761
  pthread_mutex_unlock(&stateChangeMutex);
 
1762
 
 
1763
  return(rc);
 
1764
}
 
1765
 
 
1766
/* ************************************ */
 
1767
 
 
1768
int _tryLockMutex(PthreadMutex *mutexId, char* where,
 
1769
                  char* fileName, int fileLine) {
 
1770
  int rc;
 
1771
  pid_t myPid;
 
1772
 
 
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);
 
1778
    return(-1);
 
1779
  }
 
1780
 
 
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);
 
1786
    return(-1);
 
1787
  }
 
1788
 
 
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!
 
1793
   */
 
1794
  traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: tryLockMutex() call '%s' called [0x%X@%s:%d]",
 
1795
             where, (void*)&(mutexId->mutex), fileName, fileLine);
 
1796
#endif
 
1797
 
 
1798
  if(!myGlobals.disableMutexExtraInfo) {
 
1799
    myPid = getpid();
 
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()))
 
1805
         ) {
 
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);
 
1809
      }
 
1810
    }
 
1811
 
 
1812
    strcpy(mutexId->lockAttemptFile, fileName);
 
1813
    mutexId->lockAttemptLine=fileLine;
 
1814
    mutexId->lockAttemptPid=myPid;
 
1815
 
 
1816
  }
 
1817
 
 
1818
  /*
 
1819
    Return code:
 
1820
 
 
1821
    0:    lock succesful
 
1822
    EBUSY (mutex already locked)
 
1823
  */
 
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;
 
1830
  }
 
1831
 
 
1832
  if(rc != 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);
 
1836
#endif
 
1837
  } else {
 
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);
 
1841
#endif
 
1842
 
 
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();
 
1849
 
 
1850
      if(fileName != NULL) {
 
1851
        strcpy(mutexId->lockFile, fileName);
 
1852
        mutexId->lockLine = fileLine;
 
1853
      }
 
1854
 
 
1855
      if(where != NULL) strcpy(mutexId->where, where);
 
1856
    }
 
1857
  }
 
1858
 
 
1859
  pthread_mutex_unlock(&stateChangeMutex);
 
1860
  return(rc);
 
1861
}
 
1862
 
 
1863
/* ************************************ */
 
1864
 
 
1865
int _isMutexLocked(PthreadMutex *mutexId, char* fileName, int fileLine) {
 
1866
  int rc;
 
1867
 
 
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);
 
1873
    return(-1);
 
1874
  }
 
1875
 
 
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);
 
1881
    return(-1);
 
1882
  }
 
1883
 
 
1884
#ifdef SEMAPHORE_DEBUG
 
1885
  traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: isMutexLocked() testing [0x%X@%s:%d]",
 
1886
             (void*)&(mutexId->mutex), fileName, fileLine);
 
1887
#endif
 
1888
 
 
1889
  rc = pthread_mutex_trylock(&(mutexId->mutex));
 
1890
 
 
1891
  /*
 
1892
    Return code:
 
1893
 
 
1894
    0:    lock succesful
 
1895
    EBUSY (mutex already locked)
 
1896
  */
 
1897
 
 
1898
  if(rc == 0) {
 
1899
    pthread_mutex_unlock(&(mutexId->mutex));
 
1900
    return(0);
 
1901
  } else
 
1902
    return(1);
 
1903
}
 
1904
 
 
1905
/* ************************************ */
 
1906
 
 
1907
int _releaseMutex(PthreadMutex *mutexId,
 
1908
                  char* fileName, int fileLine) {
 
1909
  int rc;
 
1910
 
 
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);
 
1916
    return(-1);
 
1917
  }
 
1918
 
 
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);
 
1924
    return(-1);
 
1925
  }
 
1926
 
 
1927
  pthread_mutex_lock(&stateChangeMutex);
 
1928
 
 
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);
 
1934
 
 
1935
  }
 
1936
 
 
1937
#ifdef SEMAPHORE_DEBUG
 
1938
  traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: releaseMutex() releasing [0x%X@%s:%d]",
 
1939
             (void*)&(mutexId->mutex), fileName, fileLine);
 
1940
#endif
 
1941
  rc = pthread_mutex_unlock(&(mutexId->mutex));
 
1942
 
 
1943
  if(rc != 0)
 
1944
    traceEvent(CONST_TRACE_ERROR, "releaseMutex() failed (rc=%d) [0x%X@%s:%d]",
 
1945
               rc, (void*)&(mutexId->mutex), fileName, fileLine);
 
1946
  else {
 
1947
    if(!myGlobals.disableMutexExtraInfo) {
 
1948
      time_t lockDuration = time(NULL) - mutexId->lockTime;
 
1949
 
 
1950
      if((mutexId->maxLockedDuration < lockDuration)
 
1951
         || (mutexId->maxLockedDurationUnlockLine == 0 /* Never set */)) {
 
1952
        mutexId->maxLockedDuration = lockDuration;
 
1953
 
 
1954
        if(fileName != NULL) {
 
1955
          strcpy(mutexId->maxLockedDurationUnlockFile, fileName);
 
1956
          mutexId->maxLockedDurationUnlockLine = fileLine;
 
1957
        }
 
1958
 
 
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);
 
1966
        }
 
1967
#endif
 
1968
      }
 
1969
    }
 
1970
 
 
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;
 
1978
      }
 
1979
    }
 
1980
  }
 
1981
 
 
1982
  pthread_mutex_unlock(&stateChangeMutex);
 
1983
 
 
1984
#ifdef SEMAPHORE_DEBUG
 
1985
  if (rc != 0)
 
1986
    traceEvent(CONST_TRACE_WARNING, "SEMAPHORE_DEBUG: releaseMutex() failed (rc=%d) [0x%X@%s:%d]",
 
1987
               (void*)&(mutexId->mutex), rc, fileName, fileLine);
 
1988
  else
 
1989
    traceEvent(CONST_TRACE_INFO, "SEMAPHORE_DEBUG: releaseMutex() succeeded [0x%X@%s:%d]",
 
1990
               (void*)&(mutexId->mutex), fileName, fileLine);
 
1991
#endif
 
1992
  return(rc);
 
1993
}
 
1994
 
 
1995
/* ************************************ */
 
1996
 
 
1997
int createCondvar(ConditionalVariable *condvarId) {
 
1998
  int rc;
 
1999
 
 
2000
  rc = pthread_mutex_init(&condvarId->mutex, NULL);
 
2001
  rc = pthread_cond_init(&condvarId->condvar, NULL);
 
2002
  condvarId->predicate = 0;
 
2003
 
 
2004
  return(rc);
 
2005
}
 
2006
 
 
2007
/* ************************************ */
 
2008
 
 
2009
void deleteCondvar(ConditionalVariable *condvarId) {
 
2010
  pthread_mutex_destroy(&condvarId->mutex);
 
2011
  pthread_cond_destroy(&condvarId->condvar);
 
2012
}
 
2013
 
 
2014
/* ************************************ */
 
2015
 
 
2016
int waitCondvar(ConditionalVariable *condvarId) {
 
2017
  int rc;
 
2018
 
 
2019
  if((rc = pthread_mutex_lock(&condvarId->mutex)) != 0)
 
2020
    return rc;
 
2021
 
 
2022
  while(condvarId->predicate <= 0) {
 
2023
    rc = pthread_cond_wait(&condvarId->condvar, &condvarId->mutex);
 
2024
  }
 
2025
 
 
2026
  condvarId->predicate--;
 
2027
 
 
2028
  rc = pthread_mutex_unlock(&condvarId->mutex);
 
2029
 
 
2030
  return rc;
 
2031
}
 
2032
 
 
2033
/* ************************************ */
 
2034
 
 
2035
int timedwaitCondvar(ConditionalVariable *condvarId, struct timespec *expiration) {
 
2036
  int rc;
 
2037
 
 
2038
  if((rc = pthread_mutex_lock(&condvarId->mutex)) != 0)
 
2039
    return rc;
 
2040
 
 
2041
  while(condvarId->predicate <= 0) {
 
2042
    rc = pthread_cond_timedwait(&condvarId->condvar, &condvarId->mutex, expiration);
 
2043
    if (rc == ETIMEDOUT) {
 
2044
      return rc;
 
2045
    }
 
2046
  }
 
2047
 
 
2048
  condvarId->predicate--;
 
2049
 
 
2050
  rc = pthread_mutex_unlock(&condvarId->mutex);
 
2051
 
 
2052
  return rc;
 
2053
}
 
2054
 
 
2055
/* ************************************ */
 
2056
 
 
2057
int signalCondvar(ConditionalVariable *condvarId) {
 
2058
  int rc;
 
2059
 
 
2060
  rc = pthread_mutex_lock(&condvarId->mutex);
 
2061
 
 
2062
  condvarId->predicate++;
 
2063
 
 
2064
  rc = pthread_mutex_unlock(&condvarId->mutex);
 
2065
  rc = pthread_cond_signal(&condvarId->condvar);
 
2066
 
 
2067
  return rc;
 
2068
}
 
2069
 
 
2070
/* ************************************ */
 
2071
 
 
2072
#ifdef HAVE_SEMAPHORE_H
 
2073
 
 
2074
int createSem(sem_t *semId, int initialValue) {
 
2075
  int rc;
 
2076
 
 
2077
  rc = sem_init(semId, 0, initialValue);
 
2078
  return(rc);
 
2079
}
 
2080
 
 
2081
/* ************************************ */
 
2082
 
 
2083
void waitSem(sem_t *semId) {
 
2084
  int rc = sem_wait(semId);
 
2085
 
 
2086
  if((rc != 0) && (errno != 4 /* Interrupted system call */))
 
2087
    traceEvent(CONST_TRACE_INFO, "waitSem failed [errno=%d/%s]", errno, strerror(errno));
 
2088
}
 
2089
 
 
2090
/* ************************************ */
 
2091
 
 
2092
int incrementSem(sem_t *semId) {
 
2093
  return(sem_post(semId));
 
2094
}
 
2095
 
 
2096
/* ************************************ */
 
2097
/*
 
2098
 * WARNING: Enabling semaphors will probably cause bugs!
 
2099
 */
 
2100
 
 
2101
int decrementSem(sem_t *semId) {
 
2102
  return(sem_trywait(semId));
 
2103
}
 
2104
 
 
2105
/* ************************************ */
 
2106
 
 
2107
int deleteSem(sem_t *semId) {
 
2108
  return(sem_destroy(semId));
 
2109
}
 
2110
#endif
 
2111
 
 
2112
#endif /* CFG_MULTITHREADED */
 
2113
#endif /* WIN32 */
 
2114
 
 
2115
/* ************************************ */
 
2116
 
 
2117
int checkCommand(char* commandName) {
 
2118
#ifdef WIN32
 
2119
  return(0);
 
2120
#else
 
2121
  char buf[256], *workBuf;
 
2122
  struct stat statBuf;
 
2123
  int rc, ecode=0;
 
2124
  FILE* fd = popen(commandName, "r");
 
2125
 
 
2126
  if(fd == NULL) {
 
2127
    traceEvent(CONST_TRACE_ERROR,
 
2128
               "External tool test failed(code=%d). Disabling %s function (popen failed).",
 
2129
               errno,
 
2130
               commandName);
 
2131
    return 0;
 
2132
  }
 
2133
 
 
2134
  rc = fgetc(fd);
 
2135
  pclose(fd);
 
2136
 
 
2137
  if(rc == EOF) {
 
2138
    traceEvent(CONST_TRACE_ERROR,
 
2139
               "External tool test failed(code=%d20). Disabling %s function (tool won't run).",
 
2140
               rc,
 
2141
               commandName);
 
2142
    return(0);
 
2143
  }
 
2144
 
 
2145
  /* ok, it can be run ... is it suid? */
 
2146
  if (snprintf(buf,
 
2147
               sizeof(buf),
 
2148
               "which %s 2>/dev/null",
 
2149
               commandName) < 0) {
 
2150
    BufferTooShort();
 
2151
    return(0);
 
2152
  }
 
2153
  rc=0;
 
2154
  fd = popen(buf, "r");
 
2155
  if (errno == 0) {
 
2156
    workBuf = fgets(buf, sizeof(buf), fd);
 
2157
    pclose(fd);
 
2158
    if(workBuf != NULL) {
 
2159
      workBuf = strchr(buf, '\n');
 
2160
      if(workBuf != NULL) workBuf[0] = '\0';
 
2161
      rc = stat(buf, &statBuf);
 
2162
      if (rc == 0) {
 
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!",
 
2167
                       commandName);
 
2168
            return(1);
 
2169
          } else {
 
2170
            ecode=7;
 
2171
          }
 
2172
        } else {
 
2173
          ecode=6;
 
2174
        }
 
2175
      } else {
 
2176
        ecode=5;
 
2177
      }
 
2178
    } else {
 
2179
      ecode=4;
 
2180
    }
 
2181
  } else {
 
2182
    pclose(fd);
 
2183
    ecode=3;
 
2184
  }
 
2185
  /* test failed ... */
 
2186
  traceEvent(CONST_TRACE_ERROR,
 
2187
             "External tool test failed(code=%d%d%d). Disabling %s function%s.",
 
2188
             rc,
 
2189
             ecode,
 
2190
             errno,
 
2191
             commandName,
 
2192
             ecode == 7 ? " (tool exists but is not suid root)" : "");
 
2193
  return(0);
 
2194
 
 
2195
#endif
 
2196
}
 
2197
 
 
2198
/* ************************************ */
 
2199
 
 
2200
char* decodeNBstring(char* theString, char *theBuffer) {
 
2201
  int i=0, j = 0, len=strlen(theString);
 
2202
 
 
2203
  while((i<len) && (theString[i] != '\0')) {
 
2204
    char encodedChar, decodedChar;
 
2205
 
 
2206
    encodedChar =  theString[i++];
 
2207
    if((encodedChar < 'A') || (encodedChar > 'Z')) break; /* Wrong character */
 
2208
 
 
2209
    encodedChar -= 'A';
 
2210
    decodedChar = encodedChar << 4;
 
2211
 
 
2212
    encodedChar =  theString[i++];
 
2213
    if((encodedChar < 'A') || (encodedChar > 'Z')) break; /* Wrong character */
 
2214
 
 
2215
    encodedChar -= 'A';
 
2216
    decodedChar |= encodedChar;
 
2217
 
 
2218
    theBuffer[j++] = decodedChar;
 
2219
  }
 
2220
 
 
2221
  theBuffer[j] = '\0';
 
2222
 
 
2223
  for(i=0; i<j; i++)
 
2224
    theBuffer[i] = (char)tolower(theBuffer[i]);
 
2225
 
 
2226
  return(theBuffer);
 
2227
}
 
2228
 
 
2229
/* ************************************ */
 
2230
 
 
2231
char* savestr(const char *str)
 
2232
{
 
2233
  u_int size;
 
2234
  char *p;
 
2235
  static char *strptr = NULL;
 
2236
  static u_int strsize = 0;
 
2237
 
 
2238
  size = strlen(str) + 1;
 
2239
  if(size > strsize) {
 
2240
    strsize = 1024;
 
2241
    if(strsize < size)
 
2242
      strsize = size;
 
2243
    strptr = (char*)malloc(strsize);
 
2244
    if(strptr == NULL) {
 
2245
      fprintf(stderr, "savestr: malloc\n");
 
2246
      exit(1);
 
2247
    }
 
2248
  }
 
2249
  (void)strncpy(strptr, str, strsize);
 
2250
  p = strptr;
 
2251
  strptr += size;
 
2252
  strsize -= size;
 
2253
  return(p);
 
2254
}
 
2255
 
 
2256
 
 
2257
/* ************************************ */
 
2258
 
 
2259
/* The function below has been inherited by tcpdump */
 
2260
 
 
2261
 
 
2262
int name_interpret(char *in, char *out, int numBytes) {
 
2263
  int ret, len;
 
2264
  char *b;
 
2265
 
 
2266
  if(numBytes <= 0) {
 
2267
    /* traceEvent(CONST_TRACE_WARNING, "name_interpret error (numBytes=%d)", numBytes); */
 
2268
    return(-1);
 
2269
  }
 
2270
 
 
2271
  len = (*in++)/2;
 
2272
  b  = out;
 
2273
  *out=0;
 
2274
 
 
2275
  if(len > 30 || len < 1) {
 
2276
    /* traceEvent(CONST_TRACE_WARNING, "name_interpret error (numBytes=%d)", numBytes); */
 
2277
    return(-1);
 
2278
  }
 
2279
 
 
2280
  while (len--) {
 
2281
    if(in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
 
2282
      *out = 0;
 
2283
      return(-1);
 
2284
    }
 
2285
 
 
2286
    *out = ((in[0]-'A')<<4) + (in[1]-'A');
 
2287
    in += 2;
 
2288
    out++;
 
2289
  }
 
2290
  ret = *(--out);
 
2291
  *out = 0;
 
2292
 
 
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';
 
2296
 
 
2297
  return(ret);
 
2298
}
 
2299
 
 
2300
 
 
2301
/* ******************************* */
 
2302
 
 
2303
char* getNwInterfaceType(int i) {
 
2304
  switch(myGlobals.device[i].datalink) {
 
2305
  case DLT_NULL:        return("No&nbsp;link-layer&nbsp;encapsulation");
 
2306
  case DLT_EN10MB:      return("Ethernet");
 
2307
  case DLT_EN3MB:       return("Experimental&nbsp;Ethernet&nbsp;(3Mb)");
 
2308
  case DLT_AX25:        return("Amateur&nbsp;Radio&nbsp;AX.25");
 
2309
  case DLT_PRONET:      return("Proteon&nbsp;ProNET&nbsp;Token&nbsp;Ring");
 
2310
  case DLT_CHAOS:       return("Chaos");
 
2311
  case DLT_IEEE802:     return("IEEE&nbsp;802&nbsp;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&nbsp;encapsulated&nbsp;ATM");
 
2317
  case DLT_RAW:         return("Raw&nbsp;IP");
 
2318
  case DLT_SLIP_BSDOS:  return("BSD/OS&nbsp;SLIP");
 
2319
  case DLT_PPP_BSDOS:   return("BSD/OS&nbsp;PPP");
 
2320
  }
 
2321
 
 
2322
  return(""); /* NOTREACHED (I hope) */
 
2323
}
 
2324
 
 
2325
/* ************************************ */
 
2326
 
 
2327
int getActualInterface(u_int deviceId) {
 
2328
  if(myGlobals.mergeInterfaces) {
 
2329
    return(myGlobals.device[0].dummyDevice == 0 ? 0 : deviceId);
 
2330
  } else
 
2331
    return(deviceId);
 
2332
}
 
2333
 
 
2334
/* ************************************ */
 
2335
 
 
2336
void resetHostsVariables(HostTraffic* el) {
 
2337
  FD_ZERO(&(el->flags));
 
2338
 
 
2339
  el->totContactedSentPeers = el->totContactedRcvdPeers = 0;
 
2340
  resetUsageCounter(&el->contactedSentPeers);
 
2341
  resetUsageCounter(&el->contactedRcvdPeers);
 
2342
  resetUsageCounter(&el->contactedRouters);
 
2343
 
 
2344
  el->vlanId = -1;
 
2345
  el->hostAS = 0;
 
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;
 
2368
 
 
2369
  el->vsanId = -1;
 
2370
  resetUsageCounter(&el->contactedSentPeers);
 
2371
  resetUsageCounter(&el->contactedRcvdPeers);
 
2372
  resetUsageCounter(&el->contactedRouters);
 
2373
 
 
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);
 
2378
 
 
2379
  if (el->secHostPkts != NULL)         free(el->secHostPkts);
 
2380
  el->secHostPkts = NULL;
 
2381
}
 
2382
 
 
2383
/* ************************************
 
2384
 *
 
2385
 * [Borrowed from tcpdump]
 
2386
 *
 
2387
 */
 
2388
u_short in_cksum(const u_short *addr, int len, u_short csum) {
 
2389
  int nleft = len;
 
2390
  const u_short *w = addr;
 
2391
  u_short answer;
 
2392
  int sum = csum;
 
2393
 
 
2394
  /*
 
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
 
2398
   *  16 bits.
 
2399
   */
 
2400
  while (nleft > 1)  {
 
2401
    sum += *w++;
 
2402
    nleft -= 2;
 
2403
  }
 
2404
  if(nleft == 1)
 
2405
    sum += htons(*(u_char *)w<<8);
 
2406
 
 
2407
  /*
 
2408
   * add back carry outs from top 16 bits to low 16 bits
 
2409
   */
 
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 */
 
2413
  return(answer);
 
2414
}
 
2415
 
 
2416
/* ****************** */
 
2417
 
 
2418
void addTimeMapping(u_int16_t transactionId,
 
2419
                    struct timeval theTime) {
 
2420
 
 
2421
  u_int idx = transactionId % CONST_NUM_TRANSACTION_ENTRIES;
 
2422
  int i=0;
 
2423
 
 
2424
#ifdef DEBUG
 
2425
  traceEvent(CONST_TRACE_INFO, "DEBUG: addTimeMapping(0x%X)", transactionId);
 
2426
#endif
 
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;
 
2431
      return;
 
2432
    } else if(myGlobals.transTimeHash[idx].transactionId == transactionId) {
 
2433
      myGlobals.transTimeHash[idx].theTime = theTime;
 
2434
      return;
 
2435
    }
 
2436
 
 
2437
    idx = (idx+1) % CONST_NUM_TRANSACTION_ENTRIES;
 
2438
  }
 
2439
}
 
2440
 
 
2441
/* ****************** */
 
2442
 
 
2443
/*
 
2444
 * The time difference in microseconds
 
2445
 */
 
2446
long delta_time (struct timeval * now,
 
2447
                 struct timeval * before) {
 
2448
  time_t delta_seconds;
 
2449
  time_t delta_microseconds;
 
2450
 
 
2451
  /*
 
2452
   * compute delta in second, 1/10's and 1/1000's second units
 
2453
   */
 
2454
  delta_seconds      = now -> tv_sec  - before -> tv_sec;
 
2455
  delta_microseconds = now -> tv_usec - before -> tv_usec;
 
2456
 
 
2457
  if(delta_microseconds < 0) {
 
2458
    /* manually carry a one from the seconds field */
 
2459
    delta_microseconds += 1000000;  /* 1e6 */
 
2460
    -- delta_seconds;
 
2461
  }
 
2462
 
 
2463
  return((delta_seconds * 1000000) + delta_microseconds);
 
2464
}
 
2465
 
 
2466
/* ****************** */
 
2467
 
 
2468
time_t getTimeMapping(u_int16_t transactionId,
 
2469
                      struct timeval theTime) {
 
2470
 
 
2471
  u_int idx = transactionId % CONST_NUM_TRANSACTION_ENTRIES;
 
2472
  int i=0;
 
2473
 
 
2474
#ifdef DEBUG
 
2475
  traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X)", transactionId);
 
2476
#endif
 
2477
 
 
2478
  /* ****************************************
 
2479
 
 
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.
 
2485
 
 
2486
  **************************************** */
 
2487
 
 
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 */
 
2492
#ifdef DEBUG
 
2493
      traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X) [diff=%d]",
 
2494
                 transactionId, (unsigned long)msDiff);
 
2495
#endif
 
2496
      return(msDiff);
 
2497
    }
 
2498
 
 
2499
    idx = (idx+1) % CONST_NUM_TRANSACTION_ENTRIES;
 
2500
  }
 
2501
 
 
2502
#ifdef DEBUG
 
2503
  traceEvent(CONST_TRACE_INFO, "DEBUG: getTimeMapping(0x%X) [not found]", transactionId);
 
2504
#endif
 
2505
  return(0); /* Not found */
 
2506
}
 
2507
 
 
2508
/* ********************************** */
 
2509
 
 
2510
void traceEvent(int eventTraceLevel, char* file,
 
2511
                int line, char * format, ...) {
 
2512
  va_list va_ap;
 
2513
  va_start (va_ap, format);
 
2514
 
 
2515
  /* Fix courtesy of "Burton M. Strauss III" <BStrauss@acm.org> */
 
2516
  if(eventTraceLevel <= myGlobals.traceLevel) {
 
2517
    time_t theTime = time(NULL);
 
2518
    struct tm t;
 
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];
 
2524
 
 
2525
    int beginFileIdx=0;
 
2526
    char *mFile = NULL;
 
2527
 
 
2528
    /* First we prepare the various fields */
 
2529
 
 
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));
 
2533
 
 
2534
    /* The file/line or 'MSGID' tag, depends on logExtra */
 
2535
    memset(bufMsgID, 0, sizeof(bufMsgID));
 
2536
 
 
2537
    if(myGlobals.traceLevel > CONST_NOISY_TRACE_LEVEL) {
 
2538
      mFile = strdup(file);
 
2539
 
 
2540
      for(beginFileIdx=strlen(mFile)-1; beginFileIdx>0; beginFileIdx--) {
 
2541
        if(mFile[beginFileIdx] == '.') mFile[beginFileIdx] = '\0'; /* Strip off .c */
 
2542
#if defined(WIN32)
 
2543
        if(mFile[beginFileIdx-1] == '\\') break;  /* Start after \ (Win32)  */
 
2544
#else
 
2545
        if(mFile[beginFileIdx-1] == '/') break;   /* Start after / (!Win32) */
 
2546
#endif
 
2547
      }
 
2548
 
 
2549
      if(myGlobals.traceLevel >= CONST_DETAIL_TRACE_LEVEL) {
 
2550
        unsigned int messageid = 0;
 
2551
        int i;
 
2552
 
 
2553
        if(snprintf(bufLineID, sizeof(bufLineID), "[%s:%d] ", &mFile[beginFileIdx], line) < 0)
 
2554
          BufferTooShort();
 
2555
        
 
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);
 
2559
        }
 
2560
        
 
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)
 
2564
          BufferTooShort();
 
2565
      }
 
2566
      
 
2567
      free(mFile);
 
2568
    }
 
2569
 
 
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;
 
2576
 
 
2577
    /* Second we prepare the complete log message into buf
 
2578
     */
 
2579
    memset(buf, 0, sizeof(buf));
 
2580
    if(snprintf(buf, sizeof(buf), "%s %s %s%s%s",
 
2581
                bufTime,
 
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** " : "",
 
2587
                bufMsg
 
2588
                ) < 0)
 
2589
      BufferTooShort();
 
2590
 
 
2591
    /* Finished preparing message fields */
 
2592
 
 
2593
    /* So, (INFO & above only) - post it to logView buffer. */
 
2594
    if ((eventTraceLevel <= CONST_INFO_TRACE_LEVEL) &&
 
2595
        (myGlobals.logView != NULL)) {
 
2596
 
 
2597
#ifdef CFG_MULTITHREADED
 
2598
#ifndef WIN32
 
2599
      if(myGlobals.logViewMutex.isInitialized)
 
2600
        pthread_mutex_lock(&myGlobals.logViewMutex.mutex);
 
2601
#endif
 
2602
#endif
 
2603
 
 
2604
      if (myGlobals.logView[myGlobals.logViewNext] != NULL)
 
2605
        free(myGlobals.logView[myGlobals.logViewNext]);
 
2606
 
 
2607
      myGlobals.logView[myGlobals.logViewNext] = strdup(buf);
 
2608
 
 
2609
      myGlobals.logViewNext = (myGlobals.logViewNext + 1) % CONST_LOG_VIEW_BUFFER_SIZE;
 
2610
 
 
2611
#ifdef CFG_MULTITHREADED
 
2612
#ifndef WIN32
 
2613
      if(myGlobals.logViewMutex.isInitialized)
 
2614
        pthread_mutex_unlock(&myGlobals.logViewMutex.mutex);
 
2615
#endif
 
2616
#endif
 
2617
 
 
2618
    }
 
2619
 
 
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...
 
2622
     */
 
2623
#ifdef WIN32
 
2624
    if(isNtopAservice) return;
 
2625
#endif
 
2626
 
 
2627
    /* Otherwise, we have two paths -
 
2628
     *   Win32/no syslog headers/syslog not enabled via -L run time switch
 
2629
     *      use: printf()
 
2630
     *   Not Win32, Have syslog headers and enabled via -L run time switch
 
2631
     *      use: syslog -
 
2632
     */
 
2633
 
 
2634
#ifdef MAKE_WITH_SYSLOG
 
2635
    if(myGlobals.useSyslog == FLAG_SYSLOG_NONE) {
 
2636
#endif
 
2637
 
 
2638
      printf("%s\n", buf);
 
2639
      fflush(stdout);
 
2640
 
 
2641
#ifdef MAKE_WITH_SYSLOG
 
2642
    } else {
 
2643
      /* Skip over time - syslog() adds it automatically) */
 
2644
      char *bufLog = &buf[strlen(bufTime)];
 
2645
 
 
2646
      /* SYSLOG and set */
 
2647
      openlog("ntop", LOG_PID, myGlobals.useSyslog);
 
2648
 
 
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);
 
2655
        break;
 
2656
      case CONST_WARNING_TRACE_LEVEL:
 
2657
        syslog(LOG_WARNING, "%s", bufLog);
 
2658
        break;
 
2659
      case CONST_ALWAYSDISPLAY_TRACE_LEVEL:
 
2660
        syslog(LOG_NOTICE, "%s", bufLog);
 
2661
        break;
 
2662
      default:
 
2663
        syslog(LOG_INFO, "%s", bufLog);
 
2664
        break;
 
2665
      }
 
2666
#else
 
2667
      syslog(LOG_ERR, "%s", bufLog);
 
2668
#endif
 
2669
      closelog();
 
2670
    }
 
2671
#endif /* MAKE_WITH_SYSLOG */
 
2672
 
 
2673
  }
 
2674
 
 
2675
  va_end (va_ap);
 
2676
}
 
2677
 
 
2678
/* ******************************************** */
 
2679
 
 
2680
char* _strncpy(char *dest, const char *src, size_t n) {
 
2681
  size_t len = strlen(src);
 
2682
 
 
2683
  if(len > (n-1))
 
2684
    len = n-1;
 
2685
 
 
2686
  memcpy(dest, src, len);
 
2687
  dest[len] = '\0';
 
2688
  return(dest);
 
2689
}
 
2690
 
 
2691
/* ******************************************** */
 
2692
 
 
2693
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
 
2694
#ifndef HAVE_STRTOK_R
 
2695
/* Reentrant string tokenizer.  Generic myGlobals.version.
 
2696
 
 
2697
Slightly modified from: glibc 2.1.3
 
2698
 
 
2699
Copyright (C) 1991, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
 
2700
This file is part of the GNU C Library.
 
2701
 
 
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.
 
2706
 
 
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.
 
2711
 
 
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.  */
 
2716
 
 
2717
char *strtok_r(char *s, const char *delim, char **save_ptr) {
 
2718
  char *token;
 
2719
 
 
2720
  if (s == NULL)
 
2721
    s = *save_ptr;
 
2722
 
 
2723
  /* Scan leading delimiters.  */
 
2724
  s += strspn (s, delim);
 
2725
  if (*s == '\0')
 
2726
    return NULL;
 
2727
 
 
2728
  /* Find the end of the token.  */
 
2729
  token = s;
 
2730
  s = strpbrk (token, delim);
 
2731
  if (s == NULL)
 
2732
    /* This token finishes the string.  */
 
2733
    *save_ptr = "";
 
2734
  else {
 
2735
    /* Terminate the token and make *SAVE_PTR point past it.  */
 
2736
    *s = '\0';
 
2737
    *save_ptr = s + 1;
 
2738
  }
 
2739
 
 
2740
  return token;
 
2741
}
 
2742
#endif
 
2743
 
 
2744
/* ********************************** */
 
2745
 
 
2746
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
 
2747
 
 
2748
int getSniffedDNSName(char *hostNumIpAddress,
 
2749
                      char *name, int maxNameLen) {
 
2750
  int found = 0;
 
2751
 
 
2752
  name[0] = 0;
 
2753
 
 
2754
  if((hostNumIpAddress[0] != '\0') && myGlobals.dnsCacheFile) {
 
2755
    datum key;
 
2756
    datum data;
 
2757
 
 
2758
    key.dptr = hostNumIpAddress;
 
2759
    key.dsize = strlen(key.dptr)+1;
 
2760
 
 
2761
    data = gdbm_fetch(myGlobals.dnsCacheFile, key);
 
2762
 
 
2763
    if(data.dptr != NULL) {
 
2764
      xstrncpy(name, data.dptr, maxNameLen);
 
2765
      free(data.dptr);
 
2766
      found = 1;
 
2767
    }
 
2768
  }
 
2769
 
 
2770
  return(found);
 
2771
}
 
2772
 
 
2773
/* ******************************** */
 
2774
 
 
2775
char *strtolower(char *s) {
 
2776
  while (*s) {
 
2777
    *s=tolower(*s);
 
2778
    s++;
 
2779
  }
 
2780
 
 
2781
  return(s);
 
2782
}
 
2783
 
 
2784
/* ******************************** */
 
2785
/*
 
2786
 *  xstrncpy() - similar to strncpy(3) but terminates string always with
 
2787
 * '\0' if (n != 0 and dst != NULL),  and doesn't do padding
 
2788
 */
 
2789
char *xstrncpy(char *dest, const char *src, size_t n) {
 
2790
  char *r = dest;
 
2791
  if (!n || !dest)
 
2792
    return dest;
 
2793
  if (src)
 
2794
    while (--n != 0 && *src != '\0')
 
2795
      *dest++ = *src++;
 
2796
  *dest = '\0';
 
2797
  return r;
 
2798
}
 
2799
 
 
2800
/* *************************************** */
 
2801
 
 
2802
int strOnlyDigits(const char *s) {
 
2803
 
 
2804
  if((*s) == '\0')
 
2805
    return 0;
 
2806
 
 
2807
  while ((*s) != '\0') {
 
2808
    if(!isdigit(*s))
 
2809
      return 0;
 
2810
    s++;
 
2811
  }
 
2812
 
 
2813
  return(1);
 
2814
}
 
2815
 
 
2816
/* ****************************************************** */
 
2817
 
 
2818
FILE* getNewRandomFile(char* fileName, int len) {
 
2819
  FILE* fd;
 
2820
 
 
2821
#ifndef WIN32
 
2822
#if 0
 
2823
  int tmpfd;
 
2824
 
 
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))
 
2829
    fd = NULL;
 
2830
#else
 
2831
  char tmpFileName[NAME_MAX];
 
2832
 
 
2833
  strcpy(tmpFileName, fileName);
 
2834
  sprintf(fileName, "%s-%lu", tmpFileName,
 
2835
          myGlobals.numHandledRequests[0]+myGlobals.numHandledRequests[1]);
 
2836
  fd = fopen(fileName, "wb");
 
2837
#endif /* 0 */
 
2838
#else
 
2839
  tmpnam(fileName);
 
2840
  fd = fopen(fileName, "wb");
 
2841
#endif
 
2842
 
 
2843
  if(fd == NULL)
 
2844
    traceEvent(CONST_TRACE_WARNING, "Unable to create temp. file (%s). ", fileName);
 
2845
 
 
2846
  return(fd);
 
2847
}
 
2848
 
 
2849
/* ****************************************************** */
 
2850
 
 
2851
/*
 
2852
  Function added in order to catch invalid
 
2853
  strings passed on the command line.
 
2854
 
 
2855
  Thanks to Bailleux Christophe <cb@grolier.fr> for
 
2856
  pointing out the finger at the problem.
 
2857
*/
 
2858
 
 
2859
void stringSanityCheck(char* string) {
 
2860
  int i, j;
 
2861
 
 
2862
  if(string == NULL)  {
 
2863
    traceEvent(CONST_TRACE_FATALERROR, "Invalid string specified.");
 
2864
    exit(-1);
 
2865
  }
 
2866
 
 
2867
  for(i=0, j=1; i<strlen(string); i++) {
 
2868
    switch(string[i]) {
 
2869
    case '%':
 
2870
    case '\\':
 
2871
      j=0;
 
2872
      break;
 
2873
    }
 
2874
  }
 
2875
 
 
2876
  if(j == 0) {
 
2877
    traceEvent(CONST_TRACE_FATALERROR, "Invalid string '%s' specified.",
 
2878
               string);
 
2879
    exit(-1);
 
2880
  }
 
2881
 
 
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';
 
2886
  }
 
2887
}
 
2888
 
 
2889
/* ****************************************************** */
 
2890
 
 
2891
/*
 
2892
  Function added in order to catch invalid (too long)
 
2893
  myGlobals.device names specified on the command line.
 
2894
 
 
2895
  Thanks to Bailleux Christophe <cb@grolier.fr> for
 
2896
  pointing out the finger at the problem.
 
2897
*/
 
2898
 
 
2899
void deviceSanityCheck(char* string) {
 
2900
  int i, j;
 
2901
 
 
2902
  if(strlen(string) > MAX_DEVICE_NAME_LEN)
 
2903
    j = 0;
 
2904
  else {
 
2905
    for(i=0, j=1; i<strlen(string); i++) {
 
2906
      switch(string[i]) {
 
2907
      case ' ':
 
2908
      case ',':
 
2909
        j=0;
 
2910
        break;
 
2911
      }
 
2912
    }
 
2913
  }
 
2914
 
 
2915
  if(j == 0) {
 
2916
    traceEvent(CONST_TRACE_FATALERROR, "Invalid device specified");
 
2917
    exit(-1);
 
2918
  }
 
2919
}
 
2920
 
 
2921
/* ****************************************************** */
 
2922
 
 
2923
#ifndef HAVE_SNPRINTF
 
2924
int snprintf(char *string, size_t maxlen, const char *format, ...) {
 
2925
  int ret=0;
 
2926
  va_list args;
 
2927
 
 
2928
  va_start(args, format);
 
2929
  vsprintf(string,format,args);
 
2930
  va_end(args);
 
2931
  return ret;
 
2932
}
 
2933
#endif
 
2934
 
 
2935
/* ************************ */
 
2936
 
 
2937
void fillDomainName(HostTraffic *el) {
 
2938
  u_int i;
 
2939
  char *ip2cc;
 
2940
 
 
2941
  if(theDomainHasBeenComputed(el))
 
2942
    return;
 
2943
 
 
2944
  accessAddrResMutex("fillDomainName");
 
2945
 
 
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;
 
2953
 
 
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();
 
2959
    return;
 
2960
  }
 
2961
 
 
2962
  ip2cc = ip2CountryCode(el->hostIpAddress);
 
2963
 
 
2964
  if((ip2cc == NULL) || (strcmp(ip2cc, "***") == 0)) {
 
2965
    /* We are unable to associate a domain with this IP address. */
 
2966
    el->ip2ccValue = NULL;
 
2967
  } else {
 
2968
    el->ip2ccValue = strdup(ip2cc);
 
2969
  }
 
2970
 
 
2971
  /* Walk back to the last . */
 
2972
  i = strlen(el->hostResolvedName)-1;
 
2973
  while(i > 0)
 
2974
    if(el->hostResolvedName[i] == '.')
 
2975
      break;
 
2976
    else
 
2977
      i--;
 
2978
 
 
2979
  /* If we have it (.), use it, otherwise use the shortDomainName set at startup
 
2980
   * last choice, leave it null from above
 
2981
   */
 
2982
  if(i > 0)
 
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;
 
2987
    while(i > 0)
 
2988
      if(myGlobals.shortDomainName[i] == '.')
 
2989
        break;
 
2990
      else
 
2991
        i--;
 
2992
    if(i > 0)
 
2993
      el->dnsTLDValue = strdup(&(myGlobals.shortDomainName[i+1]));
 
2994
  }
 
2995
 
 
2996
 
 
2997
  /* Walk Forwards to the first . */
 
2998
  for(i=0; i<strlen(el->hostResolvedName)-1; i++) {
 
2999
    if(el->hostResolvedName[i] == '.')
 
3000
      break;
 
3001
  }
 
3002
 
 
3003
  /* If we have it (.), use it, otherwise use the shortDomainName set at startup
 
3004
   * last choice, leave it null from above
 
3005
   */
 
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);
 
3010
 
 
3011
  FD_SET(FLAG_THE_DOMAIN_HAS_BEEN_COMPUTED, &el->flags);
 
3012
 
 
3013
  releaseAddrResMutex();
 
3014
  return;
 
3015
}
 
3016
 
 
3017
/* ********************************* */
 
3018
 
 
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));
 
3023
 
 
3024
  if(out == NULL) {
 
3025
    str = NULL;
 
3026
    return;
 
3027
  }
 
3028
 
 
3029
  for(i=0, idx=0; i<len; i++)
 
3030
    {
 
3031
      switch(str[i])
 
3032
        {
 
3033
        case ' ':
 
3034
        case '\t':
 
3035
          if((idx > 0)
 
3036
             && (out[idx-1] != ' ')
 
3037
             && (out[idx-1] != '\t'))
 
3038
            out[idx++] = str[i];
 
3039
          break;
 
3040
        default:
 
3041
          out[idx++] = str[i];
 
3042
          break;
 
3043
        }
 
3044
    }
 
3045
 
 
3046
  out[idx] = '\0';
 
3047
  strncpy(str, out, len);
 
3048
  free(out);
 
3049
}
 
3050
 
 
3051
/* ****************************** */
 
3052
 
 
3053
void setNBnodeNameType(HostTraffic *theHost, char nodeType,
 
3054
                       char isQuery, char* nbName) {
 
3055
  trimString(nbName);
 
3056
 
 
3057
  if((nbName == NULL) || (strlen(nbName) == 0))
 
3058
    return;
 
3059
 
 
3060
  if(strlen(nbName) >= (MAX_LEN_SYM_HOST_NAME-1)) /* (**) */
 
3061
    nbName[MAX_LEN_SYM_HOST_NAME-2] = '\0';
 
3062
 
 
3063
  if(theHost->nonIPTraffic == NULL) theHost->nonIPTraffic = (NonIPTraffic*)calloc(1, sizeof(NonIPTraffic));
 
3064
 
 
3065
  theHost->nonIPTraffic->nbNodeType = (char)nodeType;
 
3066
  /* Courtesy of Roberto F. De Luca <deluca@tandar.cnea.gov.ar> */
 
3067
 
 
3068
  theHost->nonIPTraffic->nbNodeType = (char)nodeType;
 
3069
 
 
3070
  switch(nodeType) {
 
3071
  case 0x0:  /* Workstation */
 
3072
  case 0x20: /* Server/Messenger/Main name */
 
3073
    if(!isQuery) {
 
3074
      if(theHost->nonIPTraffic->nbHostName == NULL) {
 
3075
        theHost->nonIPTraffic->nbHostName = strdup(nbName);
 
3076
        updateHostName(theHost);
 
3077
 
 
3078
        if(theHost->hostResolvedName[0] == '\0') {
 
3079
          int i;
 
3080
 
 
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);
 
3083
        }
 
3084
 
 
3085
#ifdef DEBUG
 
3086
        printf("DEBUG: nbHostName=%s [0x%X]\n", nbName, nodeType);
 
3087
#endif
 
3088
      }
 
3089
    }
 
3090
    break;
 
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);
 
3098
      }
 
3099
      break;
 
3100
    }
 
3101
  }
 
3102
 
 
3103
  if(!isQuery) {
 
3104
    switch(nodeType) {
 
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);
 
3111
    }
 
3112
  }
 
3113
}
 
3114
 
 
3115
/* ******************************************* */
 
3116
 
 
3117
void addPassiveSessionInfo(HostAddr *theHost, u_short thePort) {
 
3118
  int i;
 
3119
  time_t timeoutTime = myGlobals.actTime - PARM_PASSIVE_SESSION_MINIMUM_IDLE;
 
3120
 
 
3121
#ifdef DEBUG
 
3122
  traceEvent(CONST_TRACE_INFO, "DEBUG: Adding %ld:%d", theHost, thePort);
 
3123
#endif
 
3124
 
 
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;
 
3131
      break;
 
3132
    }
 
3133
  }
 
3134
 
 
3135
  if(i == passiveSessionsLen) {
 
3136
    /* Slot Not found */
 
3137
    traceEvent(CONST_TRACE_INFO, "Info: passiveSessions[size=%d] is full", passiveSessionsLen);
 
3138
 
 
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;
 
3143
    }
 
3144
    addrcpy(&passiveSessions[passiveSessionsLen-1].sessionHost,theHost),
 
3145
      passiveSessions[passiveSessionsLen-1].sessionPort = thePort;
 
3146
  }
 
3147
}
 
3148
 
 
3149
/* ******************************************* */
 
3150
 
 
3151
int isPassiveSession(HostAddr *theHost, u_short thePort) {
 
3152
  int i;
 
3153
 
 
3154
#ifdef DEBUG
 
3155
  traceEvent(CONST_TRACE_INFO, "DEBUG: Searching for %ld:%d",
 
3156
             theHost, thePort);
 
3157
#endif
 
3158
 
 
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;
 
3165
#ifdef DEBUG
 
3166
      traceEvent(CONST_TRACE_INFO, "DEBUG: Found passive FTP session");
 
3167
#endif
 
3168
      return(1);
 
3169
    }
 
3170
  }
 
3171
 
 
3172
  return(0);
 
3173
}
 
3174
 
 
3175
/* ******************************************* */
 
3176
 
 
3177
void initPassiveSessions(void) {
 
3178
  int len;
 
3179
 
 
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;
 
3184
}
 
3185
 
 
3186
/* ******************************* */
 
3187
 
 
3188
void termPassiveSessions(void) {
 
3189
  if(myGlobals.enableSessionHandling)
 
3190
    free(passiveSessions);
 
3191
}
 
3192
 
 
3193
/* ******************************* */
 
3194
 
 
3195
int getPortByName(ServiceEntry **theSvc, char* portName) {
 
3196
  int idx;
 
3197
 
 
3198
  for(idx=0; idx<myGlobals.numActServices; idx++) {
 
3199
 
 
3200
#ifdef DEBUG
 
3201
    if(theSvc[idx] != NULL)
 
3202
      traceEvent(CONST_TRACE_INFO, "DEBUG: %d/%s [%s]",
 
3203
                 theSvc[idx]->port,
 
3204
                 theSvc[idx]->name, portName);
 
3205
#endif
 
3206
 
 
3207
    if((theSvc[idx] != NULL)
 
3208
       && (strcmp(theSvc[idx]->name, portName) == 0))
 
3209
      return(theSvc[idx]->port);
 
3210
  }
 
3211
 
 
3212
  return(-1);
 
3213
}
 
3214
 
 
3215
/* ******************************* */
 
3216
 
 
3217
char* getPortByNumber(ServiceEntry **theSvc, int port) {
 
3218
  int idx = port % myGlobals.numActServices;
 
3219
  ServiceEntry *scan;
 
3220
 
 
3221
  for(;;) {
 
3222
    scan = theSvc[idx];
 
3223
 
 
3224
    if((scan != NULL) && (scan->port == port))
 
3225
      return(scan->name);
 
3226
    else if(scan == NULL)
 
3227
      return(NULL);
 
3228
    else
 
3229
      idx = (idx+1) % myGlobals.numActServices;
 
3230
  }
 
3231
}
 
3232
 
 
3233
/* ******************************* */
 
3234
 
 
3235
char* getPortByNum(int port, int type) {
 
3236
  char* rsp;
 
3237
 
 
3238
  if(type == IPPROTO_TCP) {
 
3239
    rsp = getPortByNumber(myGlobals.tcpSvc, port);
 
3240
  } else {
 
3241
    rsp = getPortByNumber(myGlobals.udpSvc, port);
 
3242
  }
 
3243
 
 
3244
  return(rsp);
 
3245
}
 
3246
 
 
3247
/* ******************************* */
 
3248
 
 
3249
char* getAllPortByNum(int port, char *outBuf, int outBufLen) {
 
3250
  char* rsp;
 
3251
 
 
3252
  rsp = getPortByNumber(myGlobals.tcpSvc, port); /* Try TCP first... */
 
3253
  if(rsp == NULL)
 
3254
    rsp = getPortByNumber(myGlobals.udpSvc, port);  /* ...then UDP */
 
3255
 
 
3256
  if(rsp != NULL)
 
3257
    return(rsp);
 
3258
  else {
 
3259
    if(snprintf(outBuf, outBufLen, "%d", port) < 0)
 
3260
      BufferTooShort();
 
3261
    return(outBuf);
 
3262
  }
 
3263
}
 
3264
 
 
3265
/* ******************************* */
 
3266
 
 
3267
int getAllPortByName(char* portName) {
 
3268
  int rsp;
 
3269
 
 
3270
  rsp = getPortByName(myGlobals.tcpSvc, portName); /* Try TCP first... */
 
3271
  if(rsp == -1)
 
3272
    rsp = getPortByName(myGlobals.udpSvc, portName);  /* ...then UDP */
 
3273
 
 
3274
  return(rsp);
 
3275
}
 
3276
 
 
3277
 
 
3278
/* ******************************* */
 
3279
 
 
3280
void addPortHashEntry(ServiceEntry **theSvc, int port, char* name) {
 
3281
  int idx = port % myGlobals.numActServices;
 
3282
  ServiceEntry *scan;
 
3283
 
 
3284
  for(;;) {
 
3285
    scan = theSvc[idx];
 
3286
 
 
3287
    if(scan == NULL) {
 
3288
      theSvc[idx] = (ServiceEntry*)malloc(sizeof(ServiceEntry));
 
3289
      theSvc[idx]->port = (u_short)port;
 
3290
      theSvc[idx]->name = strdup(name);
 
3291
      break;
 
3292
    } else if(scan->port == port) {
 
3293
      break; /* Already there */
 
3294
    } else
 
3295
      idx = (idx+1) % myGlobals.numActServices;
 
3296
  }
 
3297
}
 
3298
 
 
3299
/* ******************************* */
 
3300
 
 
3301
void resetUsageCounter(UsageCounter *counter) {
 
3302
  int i;
 
3303
 
 
3304
  memset(counter, 0, sizeof(UsageCounter));
 
3305
 
 
3306
  for(i=0; i<MAX_NUM_CONTACTED_PEERS; i++)
 
3307
    setEmptySerial(&counter->peersSerials[i]);
 
3308
}
 
3309
 
 
3310
/* ************************************ */
 
3311
 
 
3312
/*
 
3313
  This function has to be used to reset (i.e. initialize to
 
3314
  empty values in the correct range) HostTraffic
 
3315
  instances.
 
3316
*/
 
3317
 
 
3318
void resetSecurityHostTraffic(HostTraffic *el) {
 
3319
 
 
3320
  if(el->secHostPkts == NULL) return;
 
3321
 
 
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);
 
3345
 
 
3346
  /* ************* */
 
3347
 
 
3348
  resetUsageCounter(&el->contactedRcvdPeers);
 
3349
 
 
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);
 
3371
 
 
3372
  resetUsageCounter(&el->contactedSentPeers);
 
3373
  resetUsageCounter(&el->contactedRcvdPeers);
 
3374
  resetUsageCounter(&el->contactedRouters);
 
3375
}
 
3376
 
 
3377
/* ********************************************* */
 
3378
 
 
3379
char* mapIcmpType(int icmpType) {
 
3380
  static char icmpString[4];
 
3381
 
 
3382
  icmpType %= ICMP_MAXTYPE; /* Just to be safe... */
 
3383
 
 
3384
  switch(icmpType) {
 
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");
 
3400
  default:
 
3401
    sprintf(icmpString, "%d", icmpType);
 
3402
    return(icmpString);
 
3403
  }
 
3404
}
 
3405
 
 
3406
/* ************************************ */
 
3407
 
 
3408
/* Do not delete this line! */
 
3409
#undef incrementUsageCounter
 
3410
 
 
3411
int _incrementUsageCounter(UsageCounter *counter,
 
3412
                           HostTraffic *theHost, int actualDeviceId,
 
3413
                           char* file, int line) {
 
3414
  u_int i, found=0;
 
3415
 
 
3416
#ifdef DEBUG
 
3417
  traceEvent(CONST_TRACE_INFO, "DEBUG: incrementUsageCounter(%u) @ %s:%d",
 
3418
             peerIdx, file, line);
 
3419
#endif
 
3420
 
 
3421
  if(theHost == NULL) return(0);
 
3422
 
 
3423
  counter->value.value++;
 
3424
 
 
3425
  for(i=0; i<MAX_NUM_CONTACTED_PEERS; i++) {
 
3426
    if(emptySerial(&counter->peersSerials[i])) {
 
3427
      copySerial(&counter->peersSerials[i], &theHost->hostSerial);
 
3428
      return(1);
 
3429
      break;
 
3430
    } else if(cmpSerial(&counter->peersSerials[i], &theHost->hostSerial)) {
 
3431
      found = 1;
 
3432
      break;
 
3433
    }
 
3434
  }
 
3435
 
 
3436
  if(!found) {
 
3437
    for(i=0; i<MAX_NUM_CONTACTED_PEERS-1; i++)
 
3438
      copySerial(&counter->peersSerials[i], &counter->peersSerials[i+1]);
 
3439
 
 
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 */
 
3443
  }
 
3444
 
 
3445
  return(0);
 
3446
}
 
3447
 
 
3448
/* ******************************** */
 
3449
 
 
3450
int fetchPrefsValue(char *key, char *value, int valueLen) {
 
3451
  datum key_data;
 
3452
  datum data_data;
 
3453
 
 
3454
  if((value == NULL) || (myGlobals.capturePackets == FLAG_NTOPSTATE_TERM)) return(-1);
 
3455
 
 
3456
#ifdef DEBUG
 
3457
  traceEvent(CONST_TRACE_INFO, "DEBUG: Entering fetchPrefValue()");
 
3458
#endif
 
3459
  value[0] = '\0';
 
3460
 
 
3461
  key_data.dptr  = key;
 
3462
  key_data.dsize = strlen(key_data.dptr);
 
3463
 
 
3464
  if(myGlobals.prefsFile == NULL) {
 
3465
#ifdef DEBUG
 
3466
    traceEvent(CONST_TRACE_INFO, "DEBUG: Leaving fetchPrefValue()");
 
3467
#endif
 
3468
    return(-1); /* ntop is quitting... */
 
3469
  }
 
3470
 
 
3471
  data_data = gdbm_fetch(myGlobals.prefsFile, key_data);
 
3472
 
 
3473
  memset(value, 0, valueLen);
 
3474
 
 
3475
  if(data_data.dptr != NULL) {
 
3476
    int len = min(valueLen,data_data.dsize);
 
3477
    strncpy(value, data_data.dptr, len);
 
3478
    value[len] = '\0';
 
3479
    free(data_data.dptr);
 
3480
    /* traceEvent(CONST_TRACE_INFO, "Read %s=%s.", key, value); */
 
3481
    return(0);
 
3482
  } else
 
3483
    return(-1);
 
3484
}
 
3485
 
 
3486
/* ******************************** */
 
3487
 
 
3488
void storePrefsValue(char *key, char *value) {
 
3489
  datum key_data;
 
3490
  datum data_data;
 
3491
 
 
3492
  if((value == NULL) || (myGlobals.capturePackets == FLAG_NTOPSTATE_TERM)) return;
 
3493
 
 
3494
#ifdef DEBUG
 
3495
  traceEvent(CONST_TRACE_INFO, "DEBUG:DEBUG:  Entering storePrefsValue()");
 
3496
#endif
 
3497
 
 
3498
  memset(&key_data, 0, sizeof(key_data));
 
3499
  key_data.dptr   = key;
 
3500
  key_data.dsize  = strlen(key_data.dptr);
 
3501
 
 
3502
  memset(&data_data, 0, sizeof(data_data));
 
3503
  data_data.dptr  = value;
 
3504
  data_data.dsize = strlen(value);
 
3505
 
 
3506
  if(myGlobals.prefsFile == NULL) {
 
3507
#ifdef DEBUG
 
3508
    traceEvent(CONST_TRACE_INFO, "DEBUG: Leaving storePrefsValue()");
 
3509
#endif
 
3510
    ; /* ntop is quitting... */
 
3511
  }
 
3512
 
 
3513
  if(gdbm_store(myGlobals.prefsFile, key_data, data_data, GDBM_REPLACE) != 0)
 
3514
    traceEvent(CONST_TRACE_ERROR, "While adding %s=%s.", key, value);
 
3515
  else {
 
3516
    /* traceEvent(CONST_TRACE_INFO, "Storing %s=%s.", key, value); */
 
3517
  }
 
3518
}
 
3519
 
 
3520
/* ******************************** */
 
3521
 
 
3522
#ifndef HAVE_LOCALTIME_R
 
3523
#undef localtime
 
3524
 
 
3525
#ifdef CFG_MULTITHREADED
 
3526
static PthreadMutex localtimeMutex;
 
3527
static char localtimeMutexInitialized = 0;
 
3528
#endif
 
3529
 
 
3530
struct tm *localtime_r(const time_t *t, struct tm *tp) {
 
3531
  struct tm *theTime;
 
3532
 
 
3533
#if defined(CFG_MULTITHREADED)
 
3534
  if(!localtimeMutexInitialized) {
 
3535
    createMutex(&localtimeMutex);
 
3536
    localtimeMutexInitialized = 1;
 
3537
  }
 
3538
  accessMutex(&localtimeMutex, "localtime_r");
 
3539
#endif
 
3540
 
 
3541
  theTime = localtime(t);
 
3542
 
 
3543
  if(theTime != NULL)
 
3544
    memcpy(tp, theTime, sizeof(struct tm));
 
3545
  else
 
3546
    memset(tp, 0, sizeof(struct tm)); /* What shall I do ? */
 
3547
 
 
3548
#if defined(CFG_MULTITHREADED)
 
3549
  releaseMutex(&localtimeMutex);
 
3550
#endif
 
3551
 
 
3552
  return(tp);
 
3553
}
 
3554
#endif
 
3555
 
 
3556
/* ************************************ */
 
3557
 
 
3558
int guessHops(HostTraffic *el) {
 
3559
  int numHops = 0;
 
3560
 
 
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;
 
3567
 
 
3568
  return(numHops);
 
3569
}
 
3570
 
 
3571
/* ************************************ */
 
3572
 
 
3573
#ifndef WIN32
 
3574
#undef sleep
 
3575
 
 
3576
unsigned int ntop_sleep(unsigned int secs) {
 
3577
  unsigned int unsleptTime = secs, rest;
 
3578
 
 
3579
  while((rest = sleep(unsleptTime)) > 0)
 
3580
    unsleptTime = rest;
 
3581
 
 
3582
  return(secs);
 
3583
}
 
3584
#endif
 
3585
 
 
3586
/* *************************************** */
 
3587
 
 
3588
void unescape(char *dest, int destLen, char *url) {
 
3589
  int i, len, at;
 
3590
  unsigned int val;
 
3591
  char hex[3] = {0};
 
3592
 
 
3593
  len = strlen(url);
 
3594
  at = 0;
 
3595
  memset(dest, 0, destLen);
 
3596
  for (i = 0; i < len && at < destLen; i++) {
 
3597
    if (url[i] == '%' && i+2 < len) {
 
3598
      val = 0;
 
3599
      hex[0] = url[i+1];
 
3600
      hex[1] = url[i+2];
 
3601
      hex[2] = 0;
 
3602
      sscanf(hex, "%02x", &val);
 
3603
      i += 2;
 
3604
 
 
3605
      dest[at++] = val & 0xFF;
 
3606
    } else if(url[i] == '+') {
 
3607
      dest[at++] = ' ';
 
3608
    } else
 
3609
      dest[at++] = url[i];
 
3610
  }
 
3611
}
 
3612
 
 
3613
/* ******************************** */
 
3614
 
 
3615
void incrementTrafficCounter(TrafficCounter *ctr, Counter value) {
 
3616
  ctr->value += value, ctr->modified = 1;
 
3617
}
 
3618
 
 
3619
/* ******************************** */
 
3620
 
 
3621
void resetTrafficCounter(TrafficCounter *ctr) {
 
3622
  ctr->value = 0, ctr->modified = 0;
 
3623
}
 
3624
 
 
3625
/* ******************************** */
 
3626
 
 
3627
void allocateElementHash(int deviceId, u_short hashType) {
 
3628
  int fcmemLen = sizeof(FcFabricElementHash*)*MAX_ELEMENT_HASH;
 
3629
 
 
3630
  switch(hashType) {
 
3631
  case 2: /* VSAN */
 
3632
    if(myGlobals.device[deviceId].vsanHash == NULL) {
 
3633
      myGlobals.device[deviceId].vsanHash = (FcFabricElementHash**)malloc(fcmemLen);
 
3634
      memset(myGlobals.device[deviceId].vsanHash, 0, fcmemLen);
 
3635
    }
 
3636
    break;
 
3637
  }
 
3638
}
 
3639
 
 
3640
/* *************************************************** */
 
3641
 
 
3642
u_int numActiveSenders(u_int deviceId) {
 
3643
  u_int numSenders = 0;
 
3644
  HostTraffic *el;
 
3645
 
 
3646
  for(el=getFirstHost(deviceId);
 
3647
      el != NULL; el = getNextHost(deviceId, el)) {
 
3648
    if(broadcastHost(el) || (el->pktSent.value == 0))
 
3649
      continue;
 
3650
    else if (isFcHost (el) && (el->hostFcAddress.domain == FC_ID_SYSTEM_DOMAIN))
 
3651
      continue;
 
3652
    else
 
3653
      numSenders++;
 
3654
  }
 
3655
 
 
3656
  return(numSenders);
 
3657
}
 
3658
 
 
3659
/* *************************************************** */
 
3660
u_int numActiveVsans(u_int deviceId)
 
3661
{
 
3662
  u_int numVsans = 0, i;
 
3663
  FcFabricElementHash **theHash;
 
3664
 
 
3665
  if ((theHash = myGlobals.device[deviceId].vsanHash) == NULL) {
 
3666
    return (numVsans);
 
3667
  }
 
3668
 
 
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)
 
3673
        numVsans++;
 
3674
    }
 
3675
  }
 
3676
 
 
3677
  return (numVsans);
 
3678
}
 
3679
 
 
3680
 
 
3681
 
 
3682
/* *************************************************** */
 
3683
 
 
3684
/* Courtesy of Andreas Pfaller <apfaller@yahoo.com.au> */
 
3685
 
 
3686
u_int32_t xaton(char *s) {
 
3687
  u_int32_t a, b, c, d;
 
3688
 
 
3689
  if(4!=sscanf(s, "%d.%d.%d.%d", &a, &b, &c, &d))
 
3690
    return 0;
 
3691
  return((a&0xFF)<<24)|((b&0xFF)<<16)|((c&0xFF)<<8)|(d&0xFF);
 
3692
}
 
3693
 
 
3694
/* ******************************************************************* */
 
3695
 
 
3696
void addNodeInternal(u_int32_t ip, int prefix, char *country, int as) {
 
3697
  IPNode *p1 = NULL, *p2 = NULL;
 
3698
  int i, b;
 
3699
 
 
3700
  if(country)
 
3701
    p1 = myGlobals.countryFlagHead;
 
3702
  else
 
3703
    p1 = myGlobals.asHead;
 
3704
 
 
3705
  for(i=0; i<prefix; i++) {
 
3706
    b=(ip>>(31-i)) & 0x1;
 
3707
    if(!p1->b[b]) {
 
3708
      if(!(p2=malloc(sizeof(IPNode))))
 
3709
        exit(1);
 
3710
      memset(p2, 0, sizeof(IPNode));
 
3711
 
 
3712
      if(country != NULL)
 
3713
        myGlobals.ipCountryMem += sizeof(IPNode);
 
3714
      else
 
3715
        myGlobals.asMem += sizeof(IPNode);
 
3716
      p1->b[b]=p2;
 
3717
    }
 
3718
    else
 
3719
      p2=p1->b[b];
 
3720
 
 
3721
    p1=p2;
 
3722
  }
 
3723
 
 
3724
  if(country != NULL) {
 
3725
    if(p2->node.cc[0] == 0)
 
3726
      strncpy(p2->node.cc, country, sizeof(p2->node.cc));
 
3727
  } else {
 
3728
    if(p2->node.as == 0)
 
3729
      p2->node.as = as;
 
3730
  }
 
3731
}
 
3732
 
 
3733
/* ******************************************************************* */
 
3734
 
 
3735
char *ip2CountryCode(HostAddr ip) {
 
3736
  IPNode *p = myGlobals.countryFlagHead;
 
3737
  int i, b;
 
3738
  char *cc = "";
 
3739
  u_int32_t addr;
 
3740
 
 
3741
  if (ip.hostFamily == AF_INET6)
 
3742
    return NULL;
 
3743
  addr  = ip.Ip4Address.s_addr;
 
3744
  i = 0;
 
3745
  while(p != NULL) {
 
3746
    if(p->node.cc[0] != 0)
 
3747
      cc = p->node.cc;
 
3748
    b = (addr >>(31-i)) & 0x1;
 
3749
    p = p->b[b];
 
3750
    i++;
 
3751
  }
 
3752
 
 
3753
  return(cc);
 
3754
}
 
3755
 
 
3756
/* ******************************************************** */
 
3757
 
 
3758
#ifdef PARM_SHOW_NTOP_HEARTBEAT
 
3759
void _HEARTBEAT(int beatLevel, char* file, int line, char * format, ...) {
 
3760
  char buf[LEN_GENERAL_WORK_BUFFER];
 
3761
  va_list va_ap;
 
3762
 
 
3763
  myGlobals.heartbeatCounter++;
 
3764
 
 
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);
 
3769
    va_end(va_ap);
 
3770
 
 
3771
    traceEvent(CONST_TRACE_INFO, "HEARTBEAT(%09u)[%s:%d]: %s", myGlobals.heartbeatCounter, file, line, buf);
 
3772
  }
 
3773
}
 
3774
#endif
 
3775
 
 
3776
#ifdef MAKE_WITH_I18N
 
3777
char *i18n_xvert_locale2common(const char *input) {
 
3778
  /*
 
3779
   *  locales are                  ll[_XX][.char][@modifier]
 
3780
   *
 
3781
   *  Fix it up to our common format(ll_XX), stripped of char and modifier.
 
3782
   *
 
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.
 
3785
   *
 
3786
   */
 
3787
  char *output, *work;
 
3788
 
 
3789
  output = strdup(input);
 
3790
 
 
3791
  work = strchr(output, '.');
 
3792
  if(work != NULL) {
 
3793
    work[0] = '\0';
 
3794
  }
 
3795
  work = strchr(output, '@');
 
3796
  if(work != NULL) {
 
3797
    work[0] = '\0';
 
3798
  }
 
3799
  return output;
 
3800
}
 
3801
 
 
3802
char *i18n_xvert_acceptlanguage2common(const char *input) {
 
3803
  /*
 
3804
   *  Accept-Language: headers are ll[-XX] or ll-*
 
3805
   *
 
3806
   *  Fix it up to our common format(ll_XX), with the - swapped for a _
 
3807
   *
 
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.
 
3810
   *
 
3811
   */
 
3812
  char *output, *work;
 
3813
 
 
3814
  output = strdup(input);
 
3815
 
 
3816
  work = strchr(output, '*');
 
3817
  if(work != NULL) {
 
3818
    /* Backup to erase the - of the -* combo */
 
3819
    work--;
 
3820
    work[0] = '\0';
 
3821
  }
 
3822
  work = strchr(output, '-');
 
3823
  if(work != NULL) {
 
3824
    work[0] = '_';
 
3825
  }
 
3826
  work = strchr(output, '_');
 
3827
  if(work != NULL) {
 
3828
    while(work[0] != '\0') {
 
3829
      work[0] = toupper(work[0]);
 
3830
      work++;
 
3831
    }
 
3832
  }
 
3833
  return output;
 
3834
}
 
3835
#endif /* MAKE_WITH_I18N */
 
3836
 
 
3837
/* *************************************** */
 
3838
 
 
3839
void setHostFingerprint(HostTraffic *srcHost) {
 
3840
  FILE *fd = NULL;
 
3841
  char *WIN, *MSS, *WSS, *ttl, *flags, *work;
 
3842
  int S, N, D, T, done = 0;
 
3843
  char fingerprint[32];
 
3844
  char *strtokState;
 
3845
  u_char compressedFormat;
 
3846
 
 
3847
#ifdef FINGERPRINT_DEBUG
 
3848
  traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint(0x%08x)", srcHost);
 
3849
#endif
 
3850
 
 
3851
  if(srcHost->fingerprint == NULL) {
 
3852
    /* No fingerprint yet    */
 
3853
#ifdef FINGERPRINT_DEBUG
 
3854
    traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 1");
 
3855
#endif
 
3856
    return;
 
3857
}
 
3858
 
 
3859
#ifdef FINGERPRINT_DEBUG
 
3860
  traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() '%s'(%d)",
 
3861
             srcHost->fingerprint, strlen(srcHost->fingerprint));
 
3862
#endif
 
3863
 
 
3864
  if(srcHost->fingerprint[0] == ':') {
 
3865
    /* OS already calculated */
 
3866
#ifdef FINGERPRINT_DEBUG
 
3867
    traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 2");
 
3868
#endif
 
3869
    return;
 
3870
}
 
3871
  if(strlen(srcHost->fingerprint) < 28) {
 
3872
#ifdef FINGERPRINT_DEBUG
 
3873
    traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 3");
 
3874
#endif
 
3875
    return;
 
3876
}
 
3877
 
 
3878
  if(myGlobals.childntoppid != 0) {
 
3879
#ifdef FINGERPRINT_DEBUG
 
3880
    traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: setHostFingerprint() failed test 4");
 
3881
#endif
 
3882
    return; /* Reporting fork()ed child, don't update! */
 
3883
  }
 
3884
 
 
3885
  accessAddrResMutex("setHostFingerprint");
 
3886
 
 
3887
  if(snprintf(fingerprint, sizeof(fingerprint)-1, "%s", srcHost->fingerprint) < 0)
 
3888
    BufferTooShort();
 
3889
  strtokState = NULL;
 
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;
 
3895
  S = atoi(work);
 
3896
  work = strtok_r(NULL, ":", &strtokState);    if(!work)   goto unknownFingerprint;
 
3897
  N = atoi(work);
 
3898
  work = strtok_r(NULL, ":", &strtokState);    if(!work)   goto unknownFingerprint;
 
3899
  D = atoi(work);
 
3900
  work = strtok_r(NULL, ":", &strtokState);    if(!work)   goto unknownFingerprint;
 
3901
  T = atoi(work);
 
3902
  flags = strtok_r(NULL, ":", &strtokState);   if(!flags)  goto unknownFingerprint;
 
3903
 
 
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);
 
3907
#endif
 
3908
 
 
3909
  fd=checkForInputFile(NULL, NULL, CONST_OSFINGERPRINT_FILE, NULL, &compressedFormat);
 
3910
 
 
3911
  if(fd != NULL) {
 
3912
      char line[384];
 
3913
      char *b, *d, *ptr;
 
3914
      int numLoaded=0;
 
3915
      while(readInputFile(fd, NULL, FALSE, compressedFormat, 0, 
 
3916
            line, sizeof(line), &numLoaded) == 0) {
 
3917
 
 
3918
        if((line[0] == '\0') || (line[0] == '#') || (strlen(line) < 30)) continue;
 
3919
        line[strlen(line)-1] = '\0';
 
3920
 
 
3921
        strtokState = NULL;
 
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;
 
3928
          }
 
3929
        }
 
3930
 
 
3931
        ptr = strtok_r(NULL, ":", &strtokState); if(ptr == NULL) continue;
 
3932
        if(strcmp(ptr, ttl)) continue;
 
3933
 
 
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;
 
3938
          }
 
3939
        }
 
3940
 
 
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;
 
3951
 
 
3952
        /* NOTE
 
3953
           strlen(srcHost->fingerprint) is 29 as the fingerprint length is so
 
3954
           Example: 0212:_MSS:80:WS:0:1:0:0:A:LT
 
3955
        */
 
3956
 
 
3957
        if(srcHost->fingerprint) free(srcHost->fingerprint);
 
3958
        srcHost->fingerprint = strdup(&line[28]);
 
3959
 
 
3960
        done = 1;
 
3961
 
 
3962
        readInputFile(fd, NULL, TRUE, compressedFormat, 0, NULL, 0, &numLoaded);
 
3963
 
 
3964
        break;
 
3965
 
 
3966
      } /* while ! eof */
 
3967
  }
 
3968
#ifdef FINGERPRINT_DEBUG
 
3969
    else 
 
3970
      traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: Unable to open file");
 
3971
#endif
 
3972
 
 
3973
 
 
3974
  if(!done) {
 
3975
    /* Unknown fingerprint */
 
3976
  unknownFingerprint: /* Empty OS name */
 
3977
    srcHost->fingerprint[0] = ':', srcHost->fingerprint[1] = '\0';
 
3978
  }
 
3979
#ifdef FINGERPRINT_DEBUG
 
3980
    else 
 
3981
      traceEvent(CONST_TRACE_INFO, "FINGERPRINT_DEBUG: match! %s", srcHost->fingerprint);
 
3982
#endif
 
3983
 
 
3984
  releaseAddrResMutex();
 
3985
}
 
3986
 
 
3987
/* ************************************************ */
 
3988
 
 
3989
#ifndef MEMORY_DEBUG
 
3990
#undef gdbm_firstkey
 
3991
#undef gdbm_nextkey
 
3992
#undef gdbm_fetch
 
3993
#undef gdbm_delete
 
3994
#undef gdbm_store
 
3995
#undef gdbm_close
 
3996
 
 
3997
int ntop_gdbm_delete(GDBM_FILE g, datum d) {
 
3998
  int rc;
 
3999
 
 
4000
#ifdef CFG_MULTITHREADED
 
4001
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4002
    accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_delete");
 
4003
#endif
 
4004
 
 
4005
  rc = gdbm_delete(g, d);
 
4006
 
 
4007
#ifdef CFG_MULTITHREADED
 
4008
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4009
    releaseMutex(&myGlobals.gdbmMutex);
 
4010
#endif
 
4011
 
 
4012
  return(rc);
 
4013
}
 
4014
 
 
4015
/* ****************************************** */
 
4016
 
 
4017
datum ntop_gdbm_firstkey(GDBM_FILE g) {
 
4018
  datum theData;
 
4019
 
 
4020
  memset(&theData, 0, sizeof(theData));
 
4021
 
 
4022
#ifdef CFG_MULTITHREADED
 
4023
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4024
    accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_firstkey");
 
4025
#endif
 
4026
 
 
4027
  theData = gdbm_firstkey(g);
 
4028
 
 
4029
#ifdef CFG_MULTITHREADED
 
4030
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4031
    releaseMutex(&myGlobals.gdbmMutex);
 
4032
#endif
 
4033
 
 
4034
  return(theData);
 
4035
}
 
4036
 
 
4037
/* ****************************************** */
 
4038
 
 
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");
 
4043
#endif
 
4044
 
 
4045
  gdbm_close(g);
 
4046
 
 
4047
#ifdef CFG_MULTITHREADED
 
4048
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4049
    releaseMutex(&myGlobals.gdbmMutex);
 
4050
#endif
 
4051
}
 
4052
 
 
4053
/* ******************************************* */
 
4054
 
 
4055
datum ntop_gdbm_nextkey(GDBM_FILE g, datum d) {
 
4056
  datum theData;
 
4057
 
 
4058
  memset(&theData, 0, sizeof(theData));
 
4059
 
 
4060
#ifdef CFG_MULTITHREADED
 
4061
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4062
    accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_nextkey");
 
4063
#endif
 
4064
 
 
4065
  theData = gdbm_nextkey(g, d);
 
4066
 
 
4067
#ifdef CFG_MULTITHREADED
 
4068
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4069
    releaseMutex(&myGlobals.gdbmMutex);
 
4070
#endif
 
4071
 
 
4072
  return(theData);
 
4073
}
 
4074
 
 
4075
/* ******************************************* */
 
4076
 
 
4077
datum ntop_gdbm_fetch(GDBM_FILE g, datum d) {
 
4078
  datum theData;
 
4079
 
 
4080
  memset(&theData, 0, sizeof(theData));
 
4081
 
 
4082
#ifdef CFG_MULTITHREADED
 
4083
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4084
    accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_fetch");
 
4085
#endif
 
4086
 
 
4087
  theData = gdbm_fetch(g, d);
 
4088
 
 
4089
#ifdef CFG_MULTITHREADED
 
4090
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4091
    releaseMutex(&myGlobals.gdbmMutex);
 
4092
#endif
 
4093
 
 
4094
  return(theData);
 
4095
}
 
4096
 
 
4097
/* ******************************************* */
 
4098
 
 
4099
int ntop_gdbm_store(GDBM_FILE g, datum d, datum v, int r) {
 
4100
  int rc;
 
4101
 
 
4102
#ifdef CFG_MULTITHREADED
 
4103
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4104
    accessMutex(&myGlobals.gdbmMutex, "ntop_gdbm_store");
 
4105
#endif
 
4106
 
 
4107
  rc = gdbm_store(g, d, v, r);
 
4108
 
 
4109
#ifdef CFG_MULTITHREADED
 
4110
  if(myGlobals.gdbmMutex.isInitialized == 1) /* Mutex not yet initialized ? */
 
4111
    releaseMutex(&myGlobals.gdbmMutex);
 
4112
#endif
 
4113
 
 
4114
  return(rc);
 
4115
}
 
4116
#endif /* MEMORY_DEBUG */
 
4117
 
 
4118
/* ******************************************* */
 
4119
 
 
4120
void handleWhiteBlackListAddresses(char* addresses,
 
4121
                                   u_int32_t theNetworks[MAX_NUM_NETWORKS][3],
 
4122
                                   u_short *numNets,
 
4123
                                   char* outAddresses,
 
4124
                                   int outAddressesLen) {
 
4125
 
 
4126
  *numNets = 0;
 
4127
  if((addresses == NULL) ||(strlen(addresses) == 0) ) {
 
4128
    /* No list - return with numNets = 0 */
 
4129
    outAddresses[0]='\0';
 
4130
    return;
 
4131
  }
 
4132
 
 
4133
  handleAddressLists(addresses, theNetworks,
 
4134
                     numNets, outAddresses,
 
4135
                     outAddressesLen,
 
4136
                     CONST_HANDLEADDRESSLISTS_NETFLOW);
 
4137
}
 
4138
 
 
4139
/* ****************************** */
 
4140
 
 
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
 
4143
 *
 
4144
 *   We return 1 or 2 - DO NOT SAVE
 
4145
 *                        (1 means failed white list,
 
4146
 *                          2 means matched black list)
 
4147
 *             0      - SAVE
 
4148
 *
 
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
 
4152
 */
 
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) {
 
4157
  int rc;
 
4158
  struct in_addr workAddr;
 
4159
 
 
4160
  workAddr.s_addr = addr;
 
4161
 
 
4162
  if(numBlackNets > 0) {
 
4163
    rc = __pseudoLocalAddress(&workAddr, blackNetworks, numBlackNets);
 
4164
    if(rc == 1)
 
4165
      return 2;
 
4166
  }
 
4167
 
 
4168
  if(numWhiteNets > 0) {
 
4169
    rc = __pseudoLocalAddress(&workAddr, whiteNetworks, numWhiteNets);
 
4170
    return(1 - rc);
 
4171
  }
 
4172
 
 
4173
  return(0 /* SAVE */);
 
4174
}
 
4175
 
 
4176
#ifndef HAVE_PCAP_OPEN_DEAD
 
4177
 
 
4178
struct pcap_sf {
 
4179
  FILE *rfile;
 
4180
  int swapped;
 
4181
  int hdrsize;
 
4182
  int version_major;
 
4183
  int version_minor;
 
4184
  u_char *base;
 
4185
};
 
4186
 
 
4187
struct pcap_md {
 
4188
  struct pcap_stat stat;
 
4189
  /*XXX*/
 
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 */
 
4196
#ifdef linux
 
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 */
 
4204
#endif
 
4205
};
 
4206
 
 
4207
struct pcap {
 
4208
  int fd;
 
4209
  int snapshot;
 
4210
  int linktype;
 
4211
  int tzoff;            /* timezone offset */
 
4212
  int offset;           /* offset for proper alignment */
 
4213
 
 
4214
  struct pcap_sf sf;
 
4215
  struct pcap_md md;
 
4216
 
 
4217
  /*
 
4218
   * Read buffer.
 
4219
   */
 
4220
  int bufsize;
 
4221
  u_char *buffer;
 
4222
  u_char *bp;
 
4223
  int cc;
 
4224
 
 
4225
  /*
 
4226
   * Place holder for pcap_next().
 
4227
   */
 
4228
  u_char *pkt;
 
4229
 
 
4230
 
 
4231
  /*
 
4232
   * Placeholder for filter code if bpf not in kernel.
 
4233
   */
 
4234
  struct bpf_program fcode;
 
4235
 
 
4236
  char errbuf[PCAP_ERRBUF_SIZE];
 
4237
};
 
4238
 
 
4239
pcap_t *pcap_open_dead(int linktype, int snaplen)
 
4240
{
 
4241
  pcap_t *p;
 
4242
 
 
4243
  p = malloc(sizeof(*p));
 
4244
  if (p == NULL)
 
4245
    return NULL;
 
4246
  memset (p, 0, sizeof(*p));
 
4247
  p->fd = -1;
 
4248
  p->snapshot = snaplen;
 
4249
  p->linktype = linktype;
 
4250
  return p;
 
4251
}
 
4252
#endif
 
4253
 
 
4254
/* ******************************** */
 
4255
 
 
4256
int setSpecifiedUser(void) {
 
4257
#ifndef WIN32
 
4258
  /*
 
4259
   * set user to be as inoffensive as possible
 
4260
   */
 
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");
 
4264
    exit(-1);
 
4265
  }
 
4266
  traceEvent(CONST_TRACE_ALWAYSDISPLAY, "Now running as requested user '%s' (%d:%d)",
 
4267
             myGlobals.effectiveUserName, myGlobals.userId, myGlobals.groupId);
 
4268
 
 
4269
  if((myGlobals.userId != 0) || (myGlobals.groupId != 0)) {
 
4270
#if defined(DARWIN) || defined(FREEBSD)
 
4271
    unsigned long p;
 
4272
 
 
4273
    /*
 
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.
 
4278
    */
 
4279
 
 
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;
 
4288
    return(p);
 
4289
#else
 
4290
    return(1);
 
4291
#endif
 
4292
  } else
 
4293
    return(0);
 
4294
#else
 
4295
  return(0);
 
4296
#endif
 
4297
}
 
4298
 
 
4299
/* ******************************************************************* */
 
4300
 
 
4301
u_short ip2AS(HostAddr ip) {
 
4302
  IPNode *p;
 
4303
  int i, b;
 
4304
  u_short as=0;
 
4305
  u_int32_t addr;
 
4306
 
 
4307
  if (ip.hostFamily == AF_INET6)
 
4308
    return 0;
 
4309
 
 
4310
  addr = ip.Ip4Address.s_addr;
 
4311
 
 
4312
  p = myGlobals.asHead;
 
4313
 
 
4314
  i=0;
 
4315
  while(p!=NULL) {
 
4316
    if(p->node.as !=0 )
 
4317
      as = p->node.as;
 
4318
    b=(addr>>(31-i)) & 0x1;
 
4319
    p=p->b[b];
 
4320
    i++;
 
4321
  }
 
4322
 
 
4323
 
 
4324
#ifdef DEBUG
 
4325
  {
 
4326
    char buf[64];
 
4327
 
 
4328
    traceEvent(CONST_TRACE_INFO, "%s: %d AS", _intoa(&addr, buf, sizeof(buf)), as);
 
4329
  }
 
4330
#endif
 
4331
 
 
4332
  return as;
 
4333
}
 
4334
 
 
4335
/* ************************************ */
 
4336
 
 
4337
u_int16_t getHostAS(HostTraffic *el) {
 
4338
  return(el->hostAS || (el->hostAS = ip2AS(el->hostIpAddress)));
 
4339
}
 
4340
 
 
4341
/* ************************************ */
 
4342
 
 
4343
int emptySerial(HostSerial *a) {
 
4344
  return(a->serialType == 0);
 
4345
}
 
4346
 
 
4347
/* ********************************** */
 
4348
 
 
4349
int cmpSerial(HostSerial *a, HostSerial *b) {
 
4350
  return(!memcmp(a, b, sizeof(HostSerial)));
 
4351
}
 
4352
 
 
4353
/* ********************************** */
 
4354
 
 
4355
int copySerial(HostSerial *a, HostSerial *b) {
 
4356
  return(!memcpy(a, b, sizeof(HostSerial)));
 
4357
}
 
4358
 
 
4359
/* ********************************** */
 
4360
 
 
4361
void setEmptySerial(HostSerial *a) {
 
4362
  memset(a, 0, sizeof(HostSerial));
 
4363
}
 
4364
 
 
4365
/* ********************************* */
 
4366
 
 
4367
void addPortToList(HostTraffic *host, int *thePorts /* 0...MAX_NUM_RECENT_PORTS */, u_short port) {
 
4368
  u_short i, found;
 
4369
 
 
4370
  if(port == 0)
 
4371
    FD_SET(FLAG_HOST_IP_ZERO_PORT_TRAFFIC, &host->flags);
 
4372
 
 
4373
  for(i = 0, found = 0; i<MAX_NUM_RECENT_PORTS; i++)
 
4374
    if(thePorts[i] == port) {
 
4375
      found = 1;
 
4376
      break;
 
4377
    }
 
4378
 
 
4379
  if(!found) {
 
4380
    for(i = 0; i<(MAX_NUM_RECENT_PORTS-1); i++)
 
4381
      thePorts[i] =  thePorts[i+1];
 
4382
 
 
4383
    thePorts[MAX_NUM_RECENT_PORTS-1] = port;
 
4384
  }
 
4385
}
 
4386
 
 
4387
/* ************************************ */
 
4388
 
 
4389
#ifndef WIN32
 
4390
 
 
4391
void saveNtopPid(void) {
 
4392
  char pidFileName[NAME_MAX];
 
4393
  FILE *fd;
 
4394
 
 
4395
  myGlobals.basentoppid = getpid();
 
4396
  sprintf(pidFileName, "%s/%s",
 
4397
          getuid() ?
 
4398
          /* We're not root */ myGlobals.dbPath :
 
4399
          /* We are root */ DEFAULT_NTOP_PID_DIRECTORY,
 
4400
          DEFAULT_NTOP_PIDFILE);
 
4401
  fd = fopen(pidFileName, "wb");
 
4402
 
 
4403
  if(fd == NULL) {
 
4404
    traceEvent(CONST_TRACE_WARNING, "INIT: Unable to create pid file (%s)", pidFileName);
 
4405
  } else {
 
4406
    fprintf(fd, "%d\n", myGlobals.basentoppid);
 
4407
    fclose(fd);
 
4408
    traceEvent(CONST_TRACE_INFO, "INIT: Created pid file (%s)", pidFileName);
 
4409
  }
 
4410
}
 
4411
 
 
4412
/* ********************************** */
 
4413
 
 
4414
void removeNtopPid(void) {
 
4415
  char pidFileName[NAME_MAX];
 
4416
  int rc;
 
4417
 
 
4418
  sprintf(pidFileName, "%s/%s",
 
4419
          getuid() ?
 
4420
          /* We're not root */ myGlobals.dbPath :
 
4421
          /* We are root */ DEFAULT_NTOP_PID_DIRECTORY,
 
4422
          DEFAULT_NTOP_PIDFILE);
 
4423
  rc = unlink(pidFileName);
 
4424
  if (rc == 0) {
 
4425
    traceEvent(CONST_TRACE_INFO, "TERM: Removed pid file (%s)", pidFileName);
 
4426
  } else {
 
4427
    traceEvent(CONST_TRACE_WARNING, "TERM: Unable to remove pid file (%s)", pidFileName);
 
4428
  }
 
4429
}
 
4430
 
 
4431
#endif
 
4432
 
 
4433
/* ************************************ */
 
4434
 
 
4435
/* The following two routines have been extracted from Ethereal */
 
4436
static char *
 
4437
bytestring_to_str(const u_int8_t *ad, u_int32_t len, char punct) {
 
4438
  static char  str[3][32];
 
4439
  static char *cur;
 
4440
  char        *p;
 
4441
  int          i;
 
4442
  u_int32_t   octet;
 
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' };
 
4452
 
 
4453
  if (len < 0) {
 
4454
    return "";
 
4455
  }
 
4456
 
 
4457
  len--;
 
4458
 
 
4459
  if (cur == &str[0][0]) {
 
4460
    cur = &str[1][0];
 
4461
  } else if (cur == &str[1][0]) {
 
4462
    cur = &str[2][0];
 
4463
  } else {
 
4464
    cur = &str[0][0];
 
4465
  }
 
4466
  p = &cur[18];
 
4467
  *--p = '\0';
 
4468
  i = len;
 
4469
  for (;;) {
 
4470
    octet = ad[i];
 
4471
    *--p = hex_digits[octet&0xF];
 
4472
    octet >>= 4;
 
4473
    *--p = hex_digits[octet&0xF];
 
4474
    if (i == 0)
 
4475
      break;
 
4476
    if (punct)
 
4477
      *--p = punct;
 
4478
    i--;
 
4479
  }
 
4480
  return p;
 
4481
}
 
4482
 
 
4483
char *
 
4484
fc_to_str(const u_int8_t *ad)
 
4485
{
 
4486
  return bytestring_to_str (ad, 3, '.');
 
4487
}
 
4488
 
 
4489
char *
 
4490
fcwwn_to_str (const u_int8_t *ad)
 
4491
{
 
4492
  u_int8_t zero_wwn[LEN_WWN_ADDRESS] = {0,0,0,0,0,0,0,0};
 
4493
 
 
4494
  if (!memcmp (ad, zero_wwn, LEN_WWN_ADDRESS)) {
 
4495
    return ("N/A");
 
4496
  }
 
4497
 
 
4498
  return bytestring_to_str (ad, 8, ':');
 
4499
}
 
4500
 
 
4501
/* ************************************ */
 
4502
 
 
4503
#if defined(CFG_MULTITHREADED) && defined(MAKE_WITH_SCHED_YIELD)
 
4504
 
 
4505
#undef sched_yield
 
4506
 
 
4507
/* BStrauss - August 2003 - Check the flag and skip the call... */
 
4508
extern int ntop_sched_yield(char *file, int line) {
 
4509
 
 
4510
#ifdef DEBUG
 
4511
  static int firstTime=0;
 
4512
 
 
4513
  if(firstTime) {
 
4514
    traceEvent(CONST_TRACE_INFO, "DEBUG: firstTime in ntop_sched_yield()");
 
4515
    firstTime = 1;
 
4516
  }
 
4517
#endif
 
4518
 
 
4519
  if(!myGlobals.disableSchedYield) {
 
4520
    sched_yield();
 
4521
#ifdef DEBUG
 
4522
  } else {
 
4523
    traceEvent(CONST_TRACE_INFO, "DEBUG: skipping sched_yield()");
 
4524
#endif
 
4525
  }
 
4526
}
 
4527
 
 
4528
#endif
 
4529
 
 
4530
#ifdef EMBEDDED
 
4531
extern char *crypt (__const char *__key, __const char *__salt) {
 
4532
  return(__key);
 
4533
}
 
4534
#endif
 
4535
 
 
4536
/* ********************************* */
 
4537
 
 
4538
#ifdef WIN32
 
4539
 
 
4540
static const char *
 
4541
inet_ntop4(src, dst, size)
 
4542
     const u_char *src;
 
4543
     char *dst;
 
4544
     size_t size;
 
4545
{
 
4546
  static const char fmt[] = "%u.%u.%u.%u";
 
4547
  char tmp[sizeof "255.255.255.255"];
 
4548
  int nprinted;
 
4549
 
 
4550
  nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
 
4551
  if (nprinted < 0)
 
4552
    return (NULL);  /* we assume "errno" was set by "snprintf()" */
 
4553
  if ((size_t)nprinted > size) {
 
4554
    errno = ENOSPC;
 
4555
    return (NULL);
 
4556
  }
 
4557
  strcpy(dst, tmp);
 
4558
  return (dst);
 
4559
}
 
4560
 
 
4561
#define NS_IN6ADDRSZ 16
 
4562
 
 
4563
static const char *inet_ntop6(const u_char *src, char *dst, size_t size) {
 
4564
  /*
 
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.
 
4570
   */
 
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];
 
4574
  int i;
 
4575
 
 
4576
  /*
 
4577
   * Preprocess:
 
4578
   *      Copy the input (bytewise) array into a wordwise array.
 
4579
   *      Find the longest run of 0x00's in src[] for :: shorthanding.
 
4580
   */
 
4581
  memset(words, '\0', sizeof words);
 
4582
  for (i = 0; i < NS_IN6ADDRSZ; i++)
 
4583
    words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
 
4584
  best.base = -1;
 
4585
  cur.base = -1;
 
4586
  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
 
4587
    if (words[i] == 0) {
 
4588
      if (cur.base == -1)
 
4589
        cur.base = i, cur.len = 1;
 
4590
      else
 
4591
        cur.len++;
 
4592
    } else {
 
4593
      if (cur.base != -1) {
 
4594
        if (best.base == -1 || cur.len > best.len)
 
4595
          best = cur;
 
4596
        cur.base = -1;
 
4597
      }
 
4598
    }
 
4599
  }
 
4600
  if (cur.base != -1) {
 
4601
 
 
4602
    if (best.base == -1 || cur.len > best.len)
 
4603
      best = cur;
 
4604
  }
 
4605
  if (best.base != -1 && best.len < 2)
 
4606
    best.base = -1;
 
4607
 
 
4608
  /*
 
4609
   * Format the result.
 
4610
   */
 
4611
  tp = tmp;
 
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)) {
 
4616
      if (i == best.base)
 
4617
        *tp++ = ':';
 
4618
      continue;
 
4619
    }
 
4620
    /* Are we following an initial run of 0x00s or any real hex? */
 
4621
    if (i != 0)
 
4622
      *tp++ = ':';
 
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)))
 
4627
        return (NULL);
 
4628
      tp += strlen(tp);
 
4629
      break;
 
4630
    }
 
4631
    tp += sprintf(tp, "%x", words[i]);
 
4632
  }
 
4633
  /* Was it a trailing run of 0x00's? */
 
4634
  if (best.base != -1 && (best.base + best.len) ==
 
4635
      (NS_IN6ADDRSZ / NS_INT16SZ))
 
4636
    *tp++ = ':';
 
4637
  *tp++ = '\0';
 
4638
 
 
4639
  /*
 
4640
   * Check for overflow, copy, and we're done.
 
4641
   */
 
4642
  if ((size_t)(tp - tmp) > size) {
 
4643
    errno = ENOSPC;
 
4644
    return (NULL);
 
4645
  }
 
4646
  strcpy(dst, tmp);
 
4647
  return (dst);
 
4648
}
 
4649
 
 
4650
const char *inet_ntop(int af, const void *src, char *dst, size_t size) {
 
4651
  switch (af) {
 
4652
  case AF_INET:
 
4653
    return (inet_ntop4(src, dst, size));
 
4654
  case AF_INET6:
 
4655
    return (inet_ntop6(src, dst, size));
 
4656
  default:
 
4657
    errno = -1;
 
4658
    return (NULL);
 
4659
  }
 
4660
  /* NOTREACHED */
 
4661
}
 
4662
 
 
4663
#endif
 
4664
 
 
4665
/* *************************************************** */
 
4666
 
 
4667
u_int numActiveNxPorts (u_int deviceId) {
 
4668
  u_int numSenders = 0;
 
4669
  HostTraffic *el;
 
4670
 
 
4671
  for(el=getFirstHost(deviceId);
 
4672
      el != NULL; el = getNextHost(deviceId, el)) {
 
4673
    if (isFcHost (el) && (el->hostFcAddress.domain == FC_ID_SYSTEM_DOMAIN))
 
4674
      continue;
 
4675
    else
 
4676
      numSenders++;
 
4677
  }
 
4678
 
 
4679
  return(numSenders);
 
4680
}
 
4681
 
 
4682
/* *************************************** */
 
4683
 
 
4684
#if 0 /* Not used */
 
4685
HostTraffic* findHostByFcAddr(FcAddress *fcAddr, u_short vsanId, u_int actualDeviceId) {
 
4686
  HostTraffic *el;
 
4687
  u_int idx = hashFcHost(fcAddr, vsanId, &el, actualDeviceId);
 
4688
 
 
4689
  if(el != NULL)
 
4690
    return(el); /* Found */
 
4691
  else if(idx == FLAG_NO_PEER)
 
4692
    return(NULL);
 
4693
  else
 
4694
    el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
4695
 
 
4696
  for(; el != NULL; el = el->next) {
 
4697
    if((el->hostFcAddress.domain != 0) && (!memcmp(&el->hostFcAddress, &fcAddr, LEN_FC_ADDRESS)))
 
4698
      return(el);
 
4699
  }
 
4700
 
 
4701
  return(NULL);
 
4702
}
 
4703
#endif
 
4704
 
 
4705
/* *************************************** */
 
4706
 
 
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);
 
4711
 
 
4712
  entry = myGlobals.fcnsCacheHash[hashIdx];
 
4713
 
 
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))
 
4718
      return (entry);
 
4719
 
 
4720
    entry = entry->next;
 
4721
  }
 
4722
 
 
4723
  return (NULL);
 
4724
}
 
4725
 
 
4726
/* ************************************ */
 
4727
 
 
4728
 
 
4729
/* HTTP version file retrieval loosely based on wget from FSF
 
4730
 *
 
4731
 * Retrieve a document through HTTP protocol.
 
4732
 *
 
4733
 *    <ntopversion>
 
4734
 *      <site>www.ntop.org</site>
 
4735
 *      <stable>2.2c</stable>
 
4736
 *      <development>2.2.97</development>
 
4737
 *      <unsupported>2.2</unsupported>
 
4738
 *    </ntopversion>
 
4739
 *
 
4740
 *  However, this is very unsopisticated.  If there's any problem, something
 
4741
 *  we don't expect, etc., just report it and move on...
 
4742
 *
 
4743
 */
 
4744
 
 
4745
/* ********************************** */
 
4746
 
 
4747
/* First a bunch of helper functions to keep the main checkVersion() routine
 
4748
 * even slightly understandable...
 
4749
 */
 
4750
 
 
4751
unsigned int convertNtopVersionToNumber(char *versionString) {
 
4752
  /* This one is purely an arbitrary conversion.
 
4753
   *
 
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.
 
4757
   *
 
4758
   *  The goal is to get the following converted to ascending numeric order:
 
4759
   *
 
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
 
4761
   *
 
4762
   * e.g.:
 
4763
   *
 
4764
   *   1.3     103000000
 
4765
   *   2.1     201000000
 
4766
   *   2.1.1   201000001
 
4767
   *   2.1.2   201000002
 
4768
   *   2.1.3   201000003
 
4769
   *   2.1.50  201050000
 
4770
   *   2.1.90  201090000
 
4771
   *   2.2     202000000
 
4772
   *   2.2a    202000100
 
4773
   *   2.2b    202000200
 
4774
   *   2.2c    202000300
 
4775
   *   2.2.50  202050000
 
4776
   *   2.2.90  202090000
 
4777
   *   3.0pre1 299998001
 
4778
   *   3.0rc1  299999001
 
4779
   *   3.0rc2  299999002
 
4780
   *   3.0     300000000
 
4781
   *
 
4782
   * n.m   -> nmm000000
 
4783
   * n.m.x -> nmmyyy0xx  (if x>=50 yyy=x else xx=x)
 
4784
   * n.ml  -> nmm000l00 (where a=1, b=2, etc.)
 
4785
   */
 
4786
  unsigned int f, n=0, m=0, x=0, y=0, c=0, prerc=0;
 
4787
  unsigned char l[4];
 
4788
 
 
4789
  if (versionString == NULL) {
 
4790
    return 999999999;
 
4791
  }
 
4792
 
 
4793
  memset(&l, 0, sizeof(l));
 
4794
 
 
4795
  f = sscanf(versionString, "%u.%upre%u", &n, &m, &x);
 
4796
  if(f>=3) {
 
4797
    prerc=2;
 
4798
  } else {
 
4799
    f = sscanf(versionString, "%u.%urc%u", &n, &m, &x);
 
4800
    if(f>=3) {
 
4801
      prerc=1;
 
4802
    } else {
 
4803
      f = sscanf(versionString, "%u.%u%1[a-z].%u", &n, &m, &l, &x);
 
4804
      if(f>=3) {
 
4805
        if(l[0]>0)
 
4806
          l[0] = tolower(l[0]) - 'a' + 1;
 
4807
      } else {
 
4808
        memset(&l, 0, sizeof(l));
 
4809
        f = sscanf(versionString, "%u.%u.%u", &n, &m, &x);
 
4810
        if (f<=0) {
 
4811
          return 999999999;
 
4812
        }
 
4813
      }
 
4814
    }
 
4815
  }
 
4816
  if (x>=50) {
 
4817
    y=x;
 
4818
    x=0;
 
4819
  }
 
4820
#ifdef CHKVER_DEBUG
 
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);
 
4823
#endif
 
4824
  return n*100000000 + m*1000000 + y*1000 + l[0]*100 + x - 1000*prerc;
 
4825
}
 
4826
 
 
4827
/* ********************************** */
 
4828
 
 
4829
void displayPrivacyNotice(void) {
 
4830
  char value[8];
 
4831
 
 
4832
  /* globals.displayPrivacyNotice:
 
4833
   *
 
4834
   * 0 (or not present) means display one-time
 
4835
   * 1                  means already displayed
 
4836
   * 2                  means display every time
 
4837
   */
 
4838
  if(fetchPrefsValue("globals.displayPrivacyNotice", value, sizeof(value)) == -1) {
 
4839
    value[0]='0';
 
4840
    value[1]='\0';
 
4841
  }
 
4842
  switch (value[0]) {
 
4843
  case '0':
 
4844
    storePrefsValue("globals.displayPrivacyNotice", "1");
 
4845
    /* NO BREAK HERE... fall into next case so we do the one-time display */
 
4846
  case '2':
 
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,
 
4856
               "CHKVER: *                                                         *");
 
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. *");
 
4864
    } else {
 
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.                   *");
 
4871
    }
 
4872
    traceEvent(CONST_TRACE_ALWAYSDISPLAY,
 
4873
               "CHKVER: *                                                         *");
 
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,
 
4879
               "CHKVER: *                                                         *");
 
4880
    traceEvent(CONST_TRACE_ALWAYSDISPLAY,
 
4881
               "CHKVER: * Review the man ntop page for more information.          *");
 
4882
    traceEvent(CONST_TRACE_ALWAYSDISPLAY,
 
4883
               "CHKVER: *                                                         *");
 
4884
    traceEvent(CONST_TRACE_ALWAYSDISPLAY,
 
4885
               "CHKVER: **********************PRIVACY**NOTICE**********************");
 
4886
  }
 
4887
 
 
4888
#if (0)
 
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) \
 
4894
{ \
 
4895
  unsigned int vv; \
 
4896
  vv = convertNtopVersionToNumber(a); \
 
4897
  if (vv != b) \
 
4898
    traceEvent(CONST_TRACE_INFO, "CHKVER_TEST: cNV2N %-10s -> %10u expected %10u", a, vv, b); \
 
4899
  else \
 
4900
    traceEvent(CONST_TRACE_INFO, "CHKVER_TEST: cNV2N %-10s -> %10u OK", a, vv); \
 
4901
}
 
4902
 
 
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);
 
4923
#endif    
 
4924
}
 
4925
 
 
4926
/* ********************************** */
 
4927
 
 
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!";
 
4947
  default:
 
4948
    return "is UNKNOWN...";
 
4949
  }
 
4950
}
 
4951
 
 
4952
/* ********************************** */
 
4953
 
 
4954
/* pseudo-function to use stringification to find the xml tag */
 
4955
#define xmlextract(a) { \
 
4956
       a = strstr(next, "<" #a ">"); \
 
4957
       if (a != NULL) { \
 
4958
           a += sizeof( #a ) + 1; \
 
4959
           if (strchr(a, '<') != NULL) \
 
4960
               strchr(a, '<')[0] = '\0'; \
 
4961
       } \
 
4962
}
 
4963
 
 
4964
/* ********************************** */
 
4965
 
 
4966
void tokenizeCleanupAndAppend(char *userAgent, int userAgentLen,
 
4967
                              char *title, char *input) {
 
4968
  char *work, *token;
 
4969
  int i, j, tCount=0;
 
4970
 
 
4971
  work=strdup(input);
 
4972
 
 
4973
  strncat(userAgent, " ", (userAgentLen - strlen(userAgent) - 1));
 
4974
  strncat(userAgent, title, (userAgentLen - strlen(userAgent) - 1));
 
4975
  strncat(userAgent, "(", (userAgentLen - strlen(userAgent) - 1));
 
4976
 
 
4977
  token = strtok(work, " \t\n");
 
4978
  while (token != NULL) {
 
4979
 
 
4980
    /* No -? then it's a data value - skip */
 
4981
    if(token[0] != '-') {
 
4982
      token = strtok(NULL, " \t\n");
 
4983
      continue;
 
4984
    }
 
4985
 
 
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 */
 
4991
        break;
 
4992
      } else if(token[i] != '-')
 
4993
        token[j++] = token[i];
 
4994
    }
 
4995
    token[j]='\0';
 
4996
 
 
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");
 
5005
 
 
5006
    if((strncmp(token, "prefix", strlen("prefix")) != 0) &&
 
5007
       (strncmp(token, "sysconfdir", strlen("sysconfdir")) != 0) &&
 
5008
       (strncmp(token, "norecursion", strlen("norecursion")) != 0)) {
 
5009
      if(++tCount > 1)
 
5010
        strncat(userAgent, "; ", (userAgentLen - strlen(userAgent) - 1));
 
5011
      strncat(userAgent, token, (userAgentLen - strlen(userAgent) - 1));
 
5012
    }
 
5013
 
 
5014
    token = strtok(NULL, " \t\n");
 
5015
  }
 
5016
  strncat(userAgent, ")", (userAgentLen - strlen(userAgent) - 1));
 
5017
 
 
5018
  free(work);
 
5019
}
 
5020
 
 
5021
/* ********************************** */
 
5022
 
 
5023
void extractAndAppend(char *userAgent, int userAgentLen,
 
5024
                      char *title, char *input) {
 
5025
  char *work;
 
5026
  int i, j, dFlag=FALSE;
 
5027
 
 
5028
  work=strdup(input);
 
5029
 
 
5030
  for(j=i=0; i<strlen(work); i++) {
 
5031
    if (dFlag == TRUE) {
 
5032
      if((work[i] == ' ') ||
 
5033
         (work[i] == ',') ) {
 
5034
        break;
 
5035
      }
 
5036
      work[j++]=work[i];
 
5037
    } else if (isdigit(work[i])) {
 
5038
      dFlag = TRUE;
 
5039
      work[j++]=work[i];
 
5040
    }
 
5041
  }
 
5042
  work[j]='\0';
 
5043
 
 
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));
 
5048
 
 
5049
  free(work);
 
5050
  return;
 
5051
}
 
5052
 
 
5053
/* ********************************** */
 
5054
 
 
5055
/* ===== ===== retrieve url ===== ===== */
 
5056
 
 
5057
int retrieveVersionFile(char *versionSite, char *versionFile, char *buf, int bufLen) {
 
5058
  struct hostent *hptr;
 
5059
  char *userAgent, *space;
 
5060
  int rc, sock;
 
5061
  struct sockaddr_in addr;
 
5062
#ifdef HAVE_SYS_UTSNAME_H
 
5063
  struct utsname unameData;
 
5064
#endif
 
5065
 
 
5066
  /* Establish the connection */
 
5067
  hptr = gethostbyname(versionSite);
 
5068
  if (!hptr) {
 
5069
    traceEvent(CONST_TRACE_ERROR, "CHKVER: Unable to resolve site %s", versionSite);
 
5070
    return 1;
 
5071
  }
 
5072
#ifdef CHKVER_DEBUG
 
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);
 
5078
#endif
 
5079
 
 
5080
  /* Create socket for http GET */
 
5081
  sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
5082
  if (sock < 0) {
 
5083
    traceEvent(CONST_TRACE_ERROR,
 
5084
               "CHKVER: Unable to create socket: %s(%d)", strerror(errno), errno);
 
5085
    return 1;
 
5086
  }
 
5087
#ifdef CHKVER_DEBUG
 
5088
  traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Socket is %d", sock);
 
5089
#endif
 
5090
 
 
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);
 
5095
 
 
5096
  /* Connect the socket to the remote host.  */
 
5097
  rc = connect(sock, (struct sockaddr*)&addr, (socklen_t) sizeof(addr));
 
5098
  if (rc != 0) {
 
5099
    traceEvent(CONST_TRACE_ERROR,
 
5100
               "CHKVER: Unable to connect socket: %s(%d)", strerror(errno), errno);
 
5101
    close(sock);
 
5102
    return 1;
 
5103
  }
 
5104
#ifdef CHKVER_DEBUG
 
5105
  traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Connected");
 
5106
#endif
 
5107
 
 
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)
 
5111
    BufferTooShort();
 
5112
 
 
5113
  /* Convert any spaces in the version to +s
 
5114
   *   e.g. 2.2.98 0300 -> 2.2.98+0300
 
5115
   */
 
5116
  while ((space=strchr(userAgent, ' ')) != NULL) {
 
5117
    space[0]='+';
 
5118
  }
 
5119
 
 
5120
  strncat(userAgent, " host/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5121
  strncat(userAgent, osName, (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5122
 
 
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));
 
5126
  }
 
5127
 
 
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));
 
5131
  }
 
5132
 
 
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));
 
5137
  }
 
5138
#endif
 
5139
 
 
5140
#ifdef __GNUC__
 
5141
  /* Macros to kludge around stringing of parameters */
 
5142
#define xstr(s) str(s)
 
5143
#define str(s) #s
 
5144
 
 
5145
#if defined(__GNUC_PATCHLEVEL__)
 
5146
#define GCC_VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
 
5147
#else
 
5148
#define GCC_VERSION __GNUC__.__GNUC_MINOR__
 
5149
#endif
 
5150
  strncat(userAgent, " GCC/" xstr(GCC_VERSION) , (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5151
 
 
5152
#undef str
 
5153
#undef xstr
 
5154
#endif
 
5155
 
 
5156
  tokenizeCleanupAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "config", configure_parameters);
 
5157
  tokenizeCleanupAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "run", myGlobals.startedAs);
 
5158
 
 
5159
#ifdef HAVE_PCAP_LIB_VERSION
 
5160
  extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "libpcap", (char*)pcap_lib_version());
 
5161
#endif
 
5162
 
 
5163
#if defined(WIN32) && defined(__GNUC__)
 
5164
  /* on mingw, gdbm_version not exported by library */
 
5165
#else
 
5166
  extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "gdbm", gdbm_version);
 
5167
#endif
 
5168
 
 
5169
  /*
 
5170
   * If we've guessed at the gd version, report it
 
5171
   */
 
5172
  if(myGlobals.gdVersionGuessValue != NULL)
 
5173
    extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "gd", myGlobals.gdVersionGuessValue);
 
5174
 
 
5175
#ifdef HAVE_OPENSSL
 
5176
  extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "openssl", (char*)SSLeay_version(0));
 
5177
#endif
 
5178
 
 
5179
  extractAndAppend(userAgent, LEN_GENERAL_WORK_BUFFER, "zlib", (char*)zlibVersion());
 
5180
 
 
5181
  /* Special case for webPort+sslPort... */
 
5182
  strncat(userAgent, " access/", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5183
#ifdef HAVE_OPENSSL
 
5184
  if (myGlobals.sslPort != 0) {
 
5185
    if(myGlobals.webPort != 0)
 
5186
      strncat(userAgent, "both", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5187
    else
 
5188
      strncat(userAgent, "https", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5189
  } else
 
5190
#endif
 
5191
    if(myGlobals.webPort != 0)
 
5192
      strncat(userAgent, "http", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5193
    else
 
5194
      strncat(userAgent, "none", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5195
 
 
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));
 
5200
  } else {
 
5201
    strncat(userAgent, "null", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5202
  }
 
5203
  strncat(userAgent, ")", (LEN_GENERAL_WORK_BUFFER - strlen(userAgent) - 1));
 
5204
 
 
5205
  if(snprintf(buf, bufLen, "GET /%s HTTP/1.0\r\n"
 
5206
              "Host: %s\r\n"
 
5207
              "User-Agent: %s\r\n"
 
5208
              "Accept: %s\r\n"
 
5209
              "\r\n",
 
5210
              versionFile,
 
5211
              versionSite,
 
5212
              userAgent,
 
5213
              CONST_HTTP_ACCEPT_ALL) < 0)
 
5214
    BufferTooShort();
 
5215
 
 
5216
  free(userAgent);
 
5217
 
 
5218
  /* Send the request to server.  */
 
5219
  traceEvent(CONST_TRACE_NOISY, "CHKVER: Sending request: %s", buf);
 
5220
  rc = send(sock, buf, strlen(buf), 0);
 
5221
  if (rc < 0) {
 
5222
    traceEvent(CONST_TRACE_ERROR,
 
5223
               "CHKVER: Unable to send http request: %s(%d)", strerror(errno), errno);
 
5224
    close(sock);
 
5225
    return 1;
 
5226
  }
 
5227
 
 
5228
  /* Pickup the response -
 
5229
   * remember, buf/bufLen better be big enough to handle the whole response
 
5230
   */
 
5231
  memset(buf, 0, bufLen);
 
5232
  rc = recv(sock, buf, bufLen, 
 
5233
#ifdef WIN32
 
5234
          0
 
5235
#else
 
5236
          MSG_WAITALL
 
5237
#endif
 
5238
          );
 
5239
  if (rc < 0) {
 
5240
    traceEvent(CONST_TRACE_ERROR,
 
5241
               "CHKVER: Unable to receive http response: %s(%d)", strerror(errno), errno);
 
5242
    close(sock);
 
5243
    return 1;
 
5244
  }
 
5245
  if(rc >= bufLen) {
 
5246
    traceEvent(CONST_TRACE_ERROR,
 
5247
               "CHKVER: Unable to receive entire http response (%d/%d)- skipping",
 
5248
               rc,
 
5249
               bufLen);
 
5250
    close(sock);
 
5251
    return 1;
 
5252
  }
 
5253
 
 
5254
#ifdef CHKVER_DEBUG
 
5255
  traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: Received %d bytes '%s'", rc, buf);
 
5256
#endif
 
5257
 
 
5258
  return 0;
 
5259
}
 
5260
 
 
5261
/* ********************************** */
 
5262
 
 
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.
 
5268
   */
 
5269
 
 
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;
 
5273
 
 
5274
  next=hdr=buf;
 
5275
  while (1) {
 
5276
 
 
5277
    ++hcount;
 
5278
    hdr=next;
 
5279
 
 
5280
    for (i=0; 1; i++) {
 
5281
      if (--bufLen <= 0) {
 
5282
        traceEvent(CONST_TRACE_ERROR, "CHKVER: Past end processing http response");
 
5283
        return(0);
 
5284
      }
 
5285
      /* Cleanup whitespace */
 
5286
      if (hdr[i] == '\r' ||
 
5287
          hdr[i] == '\f' ||
 
5288
          hdr[i] == '\v') {
 
5289
        hdr[i] = ' ';
 
5290
        continue;
 
5291
      }
 
5292
      if(hdr[i] == '\n') {
 
5293
        hdr[i]=' ';
 
5294
 
 
5295
        /* Check for header continuation (not allowed on the 1st header)
 
5296
         * by looking at the character ahead.
 
5297
         */
 
5298
        if((hcount > 1) &&
 
5299
           (hdr[i+1] == '\t' || hdr[i+1] == ' ')) {
 
5300
          continue;
 
5301
        }
 
5302
 
 
5303
        /* Otherwise, set next... */
 
5304
        next=&(hdr[i+1]);
 
5305
 
 
5306
        /* Clear trailing whitespace... */
 
5307
        hdr[i--]='\0';
 
5308
        while((i>=0) && (hdr[i]==' ')) hdr[i--]='\0';
 
5309
 
 
5310
        break;
 
5311
      }
 
5312
    }
 
5313
 
 
5314
#ifdef CHKVER_DEBUG
 
5315
    traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: %3d. (%3d) '%s'", hcount, strlen(hdr), hdr);
 
5316
#endif
 
5317
 
 
5318
    /* Check for rc line.  */
 
5319
    if (hcount == 1) {
 
5320
      /* Parse the first line of server response */
 
5321
      if (hdr[0] == '\0') {
 
5322
        traceEvent(CONST_TRACE_ERROR, "CHKVER: http response: Nothing");
 
5323
        return 1;
 
5324
      }
 
5325
      /*
 
5326
       * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 
5327
       */
 
5328
      rc=-1;
 
5329
      while(hdr[0] != '\0') {
 
5330
        if(hdr[0] == ' ')
 
5331
          rc=0;
 
5332
        else if(rc == 0)
 
5333
          break;
 
5334
        hdr++;
 
5335
      }
 
5336
      while((hdr[0] != '\0') &&
 
5337
            (hdr[0] != ' ')) {
 
5338
        rc = 10*rc + hdr[0] - '0';
 
5339
        hdr++;
 
5340
      }
 
5341
      if(rc != 200) {
 
5342
        traceEvent(CONST_TRACE_WARNING,
 
5343
                   "CHKVER: http response: %d - skipping check", rc);
 
5344
        return 1;
 
5345
      }
 
5346
      traceEvent(CONST_TRACE_NOISY, "CHKVER: http response: %d", rc);
 
5347
    }
 
5348
 
 
5349
    /* Empty?  Done with the headers...  */
 
5350
    if (hdr[0] == '\0') {
 
5351
      break;
 
5352
    }
 
5353
  }
 
5354
 
 
5355
#ifdef CHKVER_DEBUG
 
5356
  traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: raw version file is %s", next);
 
5357
#endif
 
5358
 
 
5359
  /* Cleanup whitespace */
 
5360
  for (j=i=0; i<strlen(next); i++) {
 
5361
    if(next[i] == '<' &&
 
5362
       next[i+1] == '!' &&
 
5363
       next[i+2] == '-' &&
 
5364
       next[i+3] == '-') {
 
5365
      for(k=i+4; k<strlen(next)-3; k++) {
 
5366
        if(next[k] == '-' &&
 
5367
           next[k+1] == '-' &&
 
5368
           next[k+2] == '>') {
 
5369
          i=k+2;
 
5370
          break;
 
5371
        }
 
5372
      }
 
5373
      if(k<strlen(next)-3)
 
5374
        continue;
 
5375
      /* Otherwise, we never found the close... so we ignore the 'comment' */
 
5376
    }
 
5377
    if(next[i] == '\n' ||
 
5378
       next[i] == '\r' ||
 
5379
       next[i] == '\f' ||
 
5380
       next[i] == '\v' ||
 
5381
       next[i] == '\t' ||
 
5382
       next[i] == ' ') {
 
5383
    } else {
 
5384
      next[j++] = next[i];
 
5385
    }
 
5386
  }
 
5387
  next[j]='\0';
 
5388
 
 
5389
#ifdef CHKVER_DEBUG
 
5390
  traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: cleaned version file is %s", next);
 
5391
#endif
 
5392
 
 
5393
  /* parse - in reverse order so we can do it cheesy using \0s */
 
5394
  xmlextract(development);
 
5395
  xmlextract(stable);
 
5396
  xmlextract(unsupported);
 
5397
  xmlextract(obsolete);
 
5398
  xmlextract(date);
 
5399
  xmlextract(site);
 
5400
 
 
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);
 
5419
    return 1;
 
5420
  }
 
5421
 
 
5422
  traceEvent(CONST_TRACE_INFO, "CHKVER: Version file is from '%s'", site);
 
5423
  traceEvent(CONST_TRACE_INFO, "CHKVER: as of date is '%s'", date);
 
5424
 
 
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);
 
5430
 
 
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;
 
5444
  } else {
 
5445
    myGlobals.checkVersionStatus = FLAG_CHECKVERSION_NEWDEVELOPMENT;
 
5446
  }
 
5447
 
 
5448
  return 0;
 
5449
}
 
5450
 
 
5451
/* ********************************** */
 
5452
 
 
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!
 
5456
   */
 
5457
  char buf[LEN_CHECKVERSION_BUFFER];
 
5458
  int rc=0, idx = 0;  
 
5459
 
 
5460
  displayPrivacyNotice();
 
5461
 
 
5462
  if(myGlobals.skipVersionCheck == TRUE)
 
5463
    return(NULL);
 
5464
 
 
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);
 
5468
  
 
5469
#ifdef CHKVER_DEBUG
 
5470
    traceEvent(CONST_TRACE_INFO, "CHKVER_DEBUG: '%s' '%s'", versionSite[idx], CONST_VERSIONCHECK_DOCUMENT);
 
5471
#endif
 
5472
 
 
5473
    memset(buf, 0, sizeof(buf));
 
5474
  
 
5475
    rc = retrieveVersionFile(versionSite[idx], CONST_VERSIONCHECK_DOCUMENT, buf, sizeof(buf));
 
5476
    
 
5477
    if(rc == 0) break;
 
5478
  }
 
5479
 
 
5480
  if (rc == 0) {
 
5481
    rc = processVersionFile(buf, min(sizeof(buf), strlen(buf)));
 
5482
    
 
5483
    if (rc == 0) {
 
5484
      traceEvent(CONST_TRACE_INFO,
 
5485
                 "CHKVER: This version of ntop is %s", reportNtopVersionCheck());
 
5486
    }
 
5487
  }
 
5488
 
 
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
 
5492
     */
 
5493
    myGlobals.checkVersionStatusAgain = time(NULL) + CONST_VERSIONRECHECK_INTERVAL;
 
5494
  else
 
5495
    myGlobals.checkVersionStatusAgain = 0;
 
5496
 
 
5497
  return(NULL);
 
5498
}
 
5499
 
 
5500
/* ********************************** */
 
5501
 
 
5502
int readInputFile(FILE* fd,
 
5503
                    char* logTag,
 
5504
                    u_char forceClose,
 
5505
                    u_char compressedFormat,
 
5506
                    int countPer,
 
5507
                    char* buf,
 
5508
                    int bufLen,
 
5509
                    int* recordsRead) {
 
5510
 
 
5511
  /*
 
5512
   * This is a common routine to return the records from a data file, compressed or 
 
5513
   * not, which was checked for via checkForInputFile.
 
5514
   *
 
5515
   *    It returns -1 if an eof occured or zero otherwise.
 
5516
   *    The record is returned in buf.
 
5517
   *
 
5518
   * Call with forceClose TRUE to force the file to be closed...
 
5519
   */
 
5520
 
 
5521
  char* getValue;
 
5522
 
 
5523
  if((fd != NULL) && (forceClose == FALSE) && (buf != NULL) && (bufLen > 0)) {
 
5524
#ifdef MAKE_WITH_ZLIB
 
5525
      if(compressedFormat)
 
5526
        getValue = gzgets(fd, buf, bufLen);
 
5527
      else
 
5528
#endif
 
5529
        getValue = fgets(buf, bufLen, fd);
 
5530
 
 
5531
      if(getValue != NULL) {
 
5532
        (*recordsRead)++;
 
5533
        if((logTag != NULL) && (countPer > 0) && ((*recordsRead) % countPer == 0))
 
5534
          traceEvent(CONST_TRACE_NOISY, "%s: ....%6d records read", logTag, (*recordsRead));
 
5535
        return(0);
 
5536
      }
 
5537
  }
 
5538
 
 
5539
  /* Either EOF or forceClose */
 
5540
  if(logTag != NULL) 
 
5541
    traceEvent(CONST_TRACE_NOISY, "%s: Closing file", logTag);
 
5542
 
 
5543
  if(fd != NULL) 
 
5544
#ifdef MAKE_WITH_ZLIB
 
5545
    if(compressedFormat)
 
5546
      gzclose(fd);
 
5547
    else
 
5548
#endif
 
5549
      fclose(fd);
 
5550
 
 
5551
  if((logTag != NULL) && (*recordsRead > 0))
 
5552
    traceEvent(CONST_TRACE_INFO, "%s: ...found %d lines", logTag, *recordsRead);
 
5553
 
 
5554
  return(-1);
 
5555
}
 
5556
 
 
5557
/* ********************************** */
 
5558
 
 
5559
FILE* checkForInputFile(char* logTag,
 
5560
                      char* descr,
 
5561
                      char* fileName,
 
5562
                      struct stat *dbStat,
 
5563
                      u_char* compressedFormat) {
 
5564
 
 
5565
  int configFileFound=FALSE, idx;
 
5566
  char tmpFile[LEN_GENERAL_WORK_BUFFER];
 
5567
  FILE* fd;
 
5568
  struct tm t;
 
5569
  char bufTime[LEN_TIMEFORMAT_BUFFER], bufTime2[LEN_TIMEFORMAT_BUFFER];
 
5570
 
 
5571
  /*
 
5572
   * This is a common routine to look for a data file, compressed or not,
 
5573
   * in the various locations ntop looks for them.
 
5574
   *
 
5575
   *    It returns fd if a file was found.  Returned value compressedFormat tells the tale
 
5576
   *
 
5577
   *    It returns NULL if the file was not found.
 
5578
   *
 
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.
 
5581
   *
 
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.
 
5585
   */
 
5586
  if(logTag != NULL) traceEvent(CONST_TRACE_INFO, "%s: Checking for %s file", logTag, descr);
 
5587
  for(idx=0; myGlobals.configFileDirs[idx] != NULL; idx++) {
 
5588
 
 
5589
#ifdef MAKE_WITH_ZLIB
 
5590
      *compressedFormat = 1;
 
5591
      if(snprintf(tmpFile, sizeof(tmpFile),
 
5592
                  "%s%c%s.gz",
 
5593
                  myGlobals.configFileDirs[idx], CONST_PATH_SEP, fileName) < 0)
 
5594
        BufferTooShort();
 
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 */
 
5598
#endif
 
5599
 
 
5600
      if(fd == NULL) {
 
5601
        *compressedFormat = 0;
 
5602
        if(snprintf(tmpFile, sizeof(tmpFile),
 
5603
                    "%s%c%s",
 
5604
                    myGlobals.configFileDirs[idx], CONST_PATH_SEP, fileName) < 0)
 
5605
          BufferTooShort();
 
5606
        if(logTag != NULL) traceEvent(CONST_TRACE_NOISY, "%s: Checking '%s'", logTag, tmpFile);
 
5607
        fd = fopen(tmpFile, "r");
 
5608
      }
 
5609
 
 
5610
      if(fd != NULL) {
 
5611
        configFileFound = TRUE;
 
5612
        if(logTag != NULL) traceEvent(CONST_TRACE_NOISY, "%s: ...Found", logTag);
 
5613
        break;
 
5614
      }
 
5615
  } /* for */
 
5616
 
 
5617
  if (configFileFound != TRUE) {
 
5618
      if(logTag != NULL)
 
5619
        traceEvent(CONST_TRACE_WARNING, "%s: Unable to open file '%s'", logTag, fileName);
 
5620
      return(NULL);
 
5621
  }
 
5622
 
 
5623
  if(dbStat) {
 
5624
      struct stat checkStat;
 
5625
 
 
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);
 
5634
      }
 
5635
 
 
5636
      /* Check time stamps... */
 
5637
      if(!stat(tmpFile, &checkStat)) {
 
5638
        time_t compareTime;
 
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);
 
5646
        }
 
5647
        if(dbStat->st_mtime >= compareTime) {
 
5648
          if(logTag != NULL)
 
5649
            traceEvent(CONST_TRACE_INFO,"%s: File '%s' does not need to be reloaded", logTag, tmpFile);
 
5650
#ifdef MAKE_WITH_ZLIB
 
5651
          if(*compressedFormat)
 
5652
            gzclose(fd);
 
5653
          else
 
5654
#endif
 
5655
            fclose(fd);
 
5656
          return(NULL);
 
5657
        } else {
 
5658
          if(logTag != NULL)
 
5659
            traceEvent(CONST_TRACE_INFO, "%s: Loading newer file '%s'", logTag, tmpFile);
 
5660
        }
 
5661
      } else {
 
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);
 
5667
        }
 
5668
      }
 
5669
  } else {
 
5670
    if(logTag != NULL)
 
5671
      traceEvent(CONST_TRACE_INFO, "%s: Loading file '%s'", logTag, tmpFile);
 
5672
  }
 
5673
  return(fd);
 
5674
}
 
5675
 
 
5676
/* ******************************************** */
 
5677
/* Fixup routines for ethernet addresses */
 
5678
 
 
5679
void urlFixupFromRFC1945Inplace(char* url) {
 
5680
 
 
5681
/* Do an in-place fixup of a rfc1945 URL back to the internal name,
 
5682
   that is convert _s back to :s
 
5683
 */
 
5684
  int i;
 
5685
 
 
5686
  for(i=0; url[i] != '\0'; i++)
 
5687
    if(url[i] == '_')
 
5688
      url[i] = ':';
 
5689
 
 
5690
}
 
5691
 
 
5692
void urlFixupToRFC1945Inplace(char* url) {
 
5693
 
 
5694
/* Do an in-place fixup of an internal name to a RFC1945 URL, 
 
5695
   that is convert :s to _s
 
5696
 */
 
5697
  int i;
 
5698
 
 
5699
  for(i=0; url[i] != '\0'; i++)
 
5700
    if(url[i] == ':')
 
5701
      url[i] = '_';
 
5702
 
 
5703
}
 
5704
 
 
5705
/* ********************************************* */
 
5706
 
 
5707
void _setResolvedName(HostTraffic *el, char *updateValue, short updateType, char* file, int line) {
 
5708
  int i;
 
5709
 
 
5710
  if(updateValue[0] == '\0') return;
 
5711
 
 
5712
  /* Only update if this is a MORE important type */
 
5713
  if(updateType > el->hostResolvedNameType) {
 
5714
 
 
5715
#ifndef CMPFCTN_DEBUG
 
5716
    if(myGlobals.debugMode == 1)
 
5717
#endif
 
5718
      traceEvent(CONST_TRACE_INFO,
 
5719
                 "CMPFCTN_DEBUG: setResolvedName(0x%08x) %d %s -> %d %s - %s(%d)", 
 
5720
                 el,
 
5721
                 el->hostResolvedNameType,
 
5722
                 el->hostResolvedName,
 
5723
                 updateType,
 
5724
                 updateValue,
 
5725
                 file, line);
 
5726
 
 
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]);
 
5731
 
 
5732
    el->hostResolvedNameType = updateType;
 
5733
  }
 
5734
}
 
5735
 
 
5736
/* ********************************************* */
 
5737
/* ********************************************* */
 
5738
/*       hostResolvedName compare function       */
 
5739
/* ********************************************* */
 
5740
 
 
5741
int cmpFctnResolvedName(const void *_a, const void *_b) {
 
5742
 
 
5743
/* This function is ugly, but critical, so bare with...
 
5744
 
 
5745
    It takes two HostTraffic entries and performs a standardized compare
 
5746
    of the hostResolvedName fields, reaching into OTHER fields as necessary.
 
5747
 
 
5748
    The SOLE goal is to provide a stable comparison.
 
5749
 
 
5750
    Hopefully the results are PREDICTABLE and EXPLAINABLE, but that's totally
 
5751
    secondary.
 
5752
 
 
5753
    Why?  Because sorts don't handle non-transitive compares very well.
 
5754
 
 
5755
    If  A>B but B !< A, the sort will probably CHOKE.
 
5756
 
 
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...
 
5761
 
 
5762
    We also can't simply just use the next valued field in the
 
5763
    sets, because we run the risk of intransitive compares,
 
5764
    where
 
5765
 
 
5766
                    primary(a) > primary(b)
 
5767
 
 
5768
            but
 
5769
 
 
5770
                    secondary(a) < secondary(b)
 
5771
 
 
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
 
5774
    sort.
 
5775
 
 
5776
 
 
5777
    So instead in this routine, we practice a gracefull, explicit fallback:
 
5778
 
 
5779
    1. If the HostTraffic pointers are NULL, we return equality.
 
5780
 
 
5781
       1A. If one of the HostTraffic pointers is NULL, we return THAT entry as <
 
5782
 
 
5783
    2. If both of the hostResolvedName fields are NOT NULL,
 
5784
       and both of the hostResolvedNameType fields are NONE, we:
 
5785
 
 
5786
       2A. Check the hostResolvedNameType fields for both A and B.
 
5787
 
 
5788
           2A1. If they are identical, we perform the approprate 
 
5789
                apples to apples compare.  
 
5790
 
 
5791
                    For example using hostNumIpAddress for a meaningful
 
5792
                    IP address sort (where 9.0.0.0 < 10.0.0.0).
 
5793
 
 
5794
           2A2. If the hostResolvedNameType fields are NOT identical, we 
 
5795
                do the sort on the hostResolvedNameType field itself.
 
5796
 
 
5797
 
 
5798
             2A1+2A2 means that we sort all of the NAMES alphabetically, 
 
5799
             followed by all of the IP addresses sorted NUMERICALLY, followed by...
 
5800
 
 
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
 
5804
        end of the sort).
 
5805
 
 
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.
 
5809
 
 
5810
    4. Finally if nothing matches, we return a=b.
 
5811
 
 
5812
   */
 
5813
 
 
5814
    HostTraffic **a = (HostTraffic **)_a;
 
5815
    HostTraffic **b = (HostTraffic **)_b;
 
5816
    int rc;
 
5817
    char *name1, *name2;
 
5818
#ifdef CMPFCTN_DEBUG
 
5819
    char debugCmpFctn[128];
 
5820
    memset(debugCmpFctn, 0, sizeof(debugCmpFctn));
 
5821
#endif
 
5822
 
 
5823
    /* 1, 1A */
 
5824
    if((a == NULL) && (b == NULL)) {
 
5825
      return(0);
 
5826
    } else if(a == NULL) {
 
5827
      return(-1);
 
5828
    } else if(b == NULL) {
 
5829
      return(1);
 
5830
    }
 
5831
 
 
5832
    if((*a == NULL) && (*b == NULL)) {
 
5833
      return(0);
 
5834
    } else if(*a == NULL) {
 
5835
      return(-1);
 
5836
    } else if(*b == NULL) {
 
5837
      return(1);
 
5838
    }
 
5839
 
 
5840
    accessAddrResMutex("cmpFctnResolvedName");
 
5841
 
 
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)) {
 
5846
 
 
5847
#ifdef CMPFCTN_DEBUG
 
5848
      traceEvent(CONST_TRACE_INFO, "CMPFCTN_DEBUG: cmpFctn(0x%08x, 0x%08x): %d %s vs %d %s",
 
5849
                 (*a),
 
5850
                 (*b),
 
5851
                 (*a)->hostResolvedNameType,
 
5852
                 (*a)->hostResolvedName,
 
5853
                 (*b)->hostResolvedNameType,
 
5854
                 (*b)->hostResolvedName);
 
5855
#endif
 
5856
 
 
5857
      /* 2 - valid hostResolvedName */
 
5858
      if((*a)->hostResolvedNameType == (*b)->hostResolvedNameType) {
 
5859
          /* 2A1 */
 
5860
 
 
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.
 
5865
              */
 
5866
 
 
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));
 
5873
#endif
 
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));
 
5878
#endif
 
5879
          } else if((*a)->hostResolvedNameType == FLAG_HOST_SYM_ADDR_TYPE_MAC) {
 
5880
              /*
 
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
 
5887
               */
 
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));
 
5897
#endif
 
5898
                } else {
 
5899
                  rc=-1;  /* name1 (recognized) > name2 (unrecognized) */
 
5900
#ifdef CMPFCTN_DEBUG
 
5901
                  strncpy(debugCmpFctn, "2A1-MAC-2:", sizeof(debugCmpFctn));
 
5902
#endif
 
5903
                }
 
5904
              } else {
 
5905
                rc = strcasecmp(name1, name2);
 
5906
#ifdef CMPFCTN_DEBUG
 
5907
                strncpy(debugCmpFctn, "2A1-MAC", sizeof(debugCmpFctn));
 
5908
#endif
 
5909
              }
 
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 
 
5914
             * IS meaningful.
 
5915
             */
 
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));
 
5921
#endif
 
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));
 
5928
#endif
 
5929
          } else { /* FAKE */
 
5930
            name1 = (*a)->hostResolvedName;
 
5931
            name2 = (*b)->hostResolvedName;
 
5932
            rc = strcasecmp(name1, name2);
 
5933
#ifdef CMPFCTN_DEBUG
 
5934
            strncpy(debugCmpFctn, "2A1-FAKE", sizeof(debugCmpFctn));
 
5935
#endif
 
5936
          }
 
5937
      } else {
 
5938
          /* 2A2 - unequal types, so just compare the Type field */
 
5939
          if((*a)->hostResolvedNameType > (*b)->hostResolvedNameType)
 
5940
            rc = -1; /* Higher type before lower */
 
5941
          else
 
5942
            rc = 1;
 
5943
#ifdef CMPFCTN_DEBUG
 
5944
          strncpy(debugCmpFctn, "2A2!=", sizeof(debugCmpFctn));
 
5945
#endif
 
5946
      }
 
5947
    } else {
 
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 */
 
5952
        rc = -1; 
 
5953
#ifdef CMPFCTN_DEBUG
 
5954
        strncpy(debugCmpFctn, "3A-a!", sizeof(debugCmpFctn));
 
5955
#endif
 
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 */
 
5959
        rc = 1;
 
5960
#ifdef CMPFCTN_DEBUG
 
5961
        strncpy(debugCmpFctn, "3A-b!", sizeof(debugCmpFctn));
 
5962
#endif
 
5963
      } else {
 
5964
        /* 3B - hostResolvedName not set - graceful fallback using the raw fields! */
 
5965
        char nullEthAddress[LEN_ETHERNET_ADDRESS];
 
5966
        memset(&nullEthAddress, 0, LEN_ETHERNET_ADDRESS);
 
5967
 
 
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));
 
5974
#endif
 
5975
 
 
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));
 
5982
#endif
 
5983
//TODO FC??
 
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));
 
5992
#endif
 
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));
 
5998
#endif
 
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));
 
6004
#endif
 
6005
          } else {
 
6006
            rc=0;  /* can't tell 'em apart... trouble */
 
6007
#ifdef CMPFCTN_DEBUG
 
6008
            strncpy(debugCmpFctn, "3B-0", sizeof(debugCmpFctn));
 
6009
#endif
 
6010
          }
 
6011
        } else if(((*a)->nonIPTraffic == NULL) && ((*b)->nonIPTraffic != NULL)) {
 
6012
          /* a null, b not so return a>b */
 
6013
          rc=1;
 
6014
#ifdef CMPFCTN_DEBUG
 
6015
          strncpy(debugCmpFctn, "3B-b!", sizeof(debugCmpFctn));
 
6016
#endif
 
6017
        } else if(((*a)->nonIPTraffic != NULL) && ((*b)->nonIPTraffic == NULL)) {
 
6018
          /* b null, a not so return a>b */
 
6019
          rc=1; 
 
6020
#ifdef CMPFCTN_DEBUG
 
6021
          strncpy(debugCmpFctn, "3B-a!", sizeof(debugCmpFctn));
 
6022
#endif
 
6023
        } else {
 
6024
          rc=0; /* nothing we can compare */
 
6025
#ifdef CMPFCTN_DEBUG
 
6026
          strncpy(debugCmpFctn, "3B-null", sizeof(debugCmpFctn));
 
6027
#endif
 
6028
        }
 
6029
      }
 
6030
    }
 
6031
 
 
6032
    releaseAddrResMutex();
 
6033
 
 
6034
#ifdef CMPFCTN_DEBUG
 
6035
    traceEvent(CONST_TRACE_INFO, "CMPFCTN_DEBUG: cmpFctn(): %s rc=%d", debugCmpFctn, rc);
 
6036
#endif
 
6037
 
 
6038
    return(rc); 
 
6039
}
 
6040
 
 
6041
/* ********************************************* */
 
6042
/* ********************************************* */
 
6043
/*       Location code compare function          */
 
6044
/* ********************************************* */
 
6045
 
 
6046
int cmpFctnLocationName(const void *_a, const void *_b) {
 
6047
 
 
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.
 
6052
 
 
6053
   We translate 'loc' (rfc1918 addresses) to sort next to last
 
6054
   and unvalued items to sort last.
 
6055
 
 
6056
   Equal valued names are sorted based first on full domain name, then
 
6057
   on hostResolvedName as the tie breakers.
 
6058
 */
 
6059
 
 
6060
    HostTraffic **a = (HostTraffic **)_a;
 
6061
    HostTraffic **b = (HostTraffic **)_b;
 
6062
    int rc;
 
6063
    char *nameA, *nameB;
 
6064
 
 
6065
    rc=0;
 
6066
 
 
6067
    if((*a)->ip2ccValue == NULL) {
 
6068
        nameA = "\xFF\xFF";
 
6069
    } else if(strcasecmp((*a)->ip2ccValue, "loc") == 0) {
 
6070
        nameA = "\xFF\xFE";
 
6071
    } else {
 
6072
        nameA = (*a)->ip2ccValue;
 
6073
    }
 
6074
    if((*b)->ip2ccValue == NULL) {
 
6075
        nameB = "\xFF\xFF";
 
6076
    } else if(strcasecmp((*b)->ip2ccValue, "loc") == 0) {
 
6077
        nameB = "\xFF\xFE";
 
6078
    } else {
 
6079
        nameB = (*b)->ip2ccValue;
 
6080
    }
 
6081
 
 
6082
    rc = strcasecmp(nameA, nameB);
 
6083
    if(rc==0) {
 
6084
      if((*a)->dnsTLDValue == NULL) {
 
6085
        nameA = "\xFF\xFF";
 
6086
      } else {
 
6087
        nameA = (*a)->dnsTLDValue;
 
6088
      }
 
6089
      if((*b)->dnsTLDValue == NULL) {
 
6090
        nameB = "\xFF\xFF";
 
6091
      } else {
 
6092
        nameB = (*b)->ip2ccValue;
 
6093
      }
 
6094
      rc = strcasecmp(nameA, nameB);
 
6095
    }
 
6096
 
 
6097
    if(rc==0) {
 
6098
      rc=cmpFctnResolvedName(a, b);
 
6099
    }
 
6100
 
 
6101
    return(rc);
 
6102
}
 
6103
 
 
6104
/* ************************************ */