--- ../arpwatch.orig/db.c Sat Sep 30 19:39:58 2000 +++ ./db.c Mon Sep 15 13:17:07 2003 @@ -41,6 +41,7 @@ #include #include #include +#include #include "gnuc.h" #ifdef HAVE_OS_PROTO_H @@ -54,18 +55,9 @@ #include "report.h" #include "util.h" -#define HASHSIZE (2 << 15) - #define NEWACTIVITY_DELTA (6*30*24*60*60) /* 6 months in seconds */ #define FLIPFLIP_DELTA (24*60*60) /* 24 hours in seconds */ -/* Ethernet info */ -struct einfo { - u_char e[6]; /* ether address */ - char h[34]; /* simple hostname */ - time_t t; /* timestamp */ -}; - /* Address info */ struct ainfo { u_int32_t a; /* ip address */ @@ -78,22 +70,69 @@ /* Address hash table */ static struct ainfo ainfo_table[HASHSIZE]; + +/* Ethernet hash table */ +struct einfo einfo_table[HASHSIZE]; +int et_cnt = 0; + static void alist_alloc(struct ainfo *); int cmpeinfo(const void *, const void *); -static struct einfo *elist_alloc(u_int32_t, u_char *, time_t, char *); +static struct einfo *elist_alloc(u_int32_t, u_char *, time_t, char *, char *); static struct ainfo *ainfo_find(u_int32_t); +static struct einfo *einfo_find(u_char *); static void check_hname(struct ainfo *); struct ainfo *newainfo(void); +pthread_mutex_t mtx_einfo, mtx_ainfo; + int -ent_add(register u_int32_t a, register u_char *e, time_t t, register char *h) +ent_add(register u_int32_t a, register u_char *e, time_t t, register char *h, register char *interface) { register struct ainfo *ap; - register struct einfo *ep; + struct einfo *ep; register int i; register u_int len; u_char *e2; time_t t2; + register evt_type event = NULL; + char *if2 = NULL; + + pthread_mutex_lock(&mtx_einfo); + + /* Lookup ethernet address */ + ep = einfo_find(e); + + /* New einfo? (elist_alloc makes 16 at a time -- no thanks) */ + if (ep == NULL && ! initializing) { + if (et_cnt >= HASHSIZE) { + syslog(LOG_ERR, "ERROR: einfo_table too big"); + } else { + ep = &einfo_table[et_cnt++]; + BCOPY(e, ep->e, sizeof(ep->e)); + if (h == NULL) + h = getsname(a); + if (h != NULL && !isdigit((int)*h)) + strncpy(ep->h, h, sizeof(ep->h)); + ep->t = t; + strncpy(ep->iface, interface, sizeof(ep->iface)); + event |= ETHER_NEW; + e2 = NULL; + t2 = NULL; + } + } else if (! initializing) { + if (strncmp(ep->iface, interface, sizeof(ep->iface)) != 0) { + event |= ETHER_IFCHG; + asprintf(&if2, "%s", ep->iface); + memset((char *)ep->iface, 0, sizeof(ep->iface)); + BCOPY(interface, ep->iface, sizeof(ep->iface)); + e2 = NULL; + t2 = ep->t; + ep->t = t; + } + } + + pthread_mutex_unlock(&mtx_einfo); + pthread_mutex_lock(&mtx_ainfo); /* Lookup ip address */ ap = ainfo_find(a); @@ -101,28 +140,30 @@ /* Check for the usual case first */ if (ap->ecount > 0) { ep = ap->elist[0]; - if (MEMCMP(e, ep->e, 6) == 0) { + if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) { if (t - ep->t > NEWACTIVITY_DELTA) { - report("new activity", a, e, NULL, &t, &ep->t); + event |= ACTIVITY_NEW; + e2 = NULL; + t2 = ep->t; check_hname(ap); } ep->t = t; - return (1); } } /* Check for a virgin ainfo record */ if (ap->ecount == 0) { ap->ecount = 1; - ap->elist[0] = elist_alloc(a, e, t, h); - report("new station", a, e, NULL, &t, NULL); - return (1); + ap->elist[0] = elist_alloc(a, e, t, h, interface); + event |= IP_NEW; + e2 = NULL; + t2 = NULL; } /* Check for a flip-flop */ if (ap->ecount > 1) { ep = ap->elist[1]; - if (MEMCMP(e, ep->e, 6) == 0) { + if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) { /* * Suppress report when less than * FLIPFLOP_DELTA and one of the two ethernet @@ -131,48 +172,76 @@ t2 = ap->elist[0]->t; e2 = ap->elist[0]->e; if (t - t2 < FLIPFLIP_DELTA && - (isdecnet(e) || isdecnet(e2))) + (isdecnet(e) || isdecnet(e2))) { dosyslog(LOG_INFO, "suppressed DECnet flip flop", a, e, e2); - else - report("flip flop", a, e, e2, &t, &t2); + event |= FLIPFLOP_DECNET; + } else { + event |= FLIPFLOP; + } + ap->elist[1] = ap->elist[0]; ap->elist[0] = ep; ep->t = t; check_hname(ap); - return (1); } } for (i = 2; i < ap->ecount; ++i) { ep = ap->elist[i]; - if (MEMCMP(e, ep->e, 6) == 0) { + if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) { /* An old entry comes to life */ e2 = ap->elist[0]->e; t2 = ap->elist[0]->t; dosyslog(LOG_NOTICE, "reused old ethernet address", a, e, e2); + event |= IP_ETHER_REUSE; /* Shift entries down */ len = i * sizeof(ap->elist[0]); BCOPY(&ap->elist[0], &ap->elist[1], len); ap->elist[0] = ep; ep->t = t; check_hname(ap); - return (1); } } - /* New ether address */ - e2 = ap->elist[0]->e; - t2 = ap->elist[0]->t; - report("changed ethernet address", a, e, e2, &t, &t2); - /* Make room at head of list */ - alist_alloc(ap); - len = ap->ecount * sizeof(ap->elist[0]); - BCOPY(&ap->elist[0], &ap->elist[1], len); - ap->elist[0] = elist_alloc(a, e, t, h); - ++ap->ecount; - return (1); + /* as originally written, any of these conditions would cause this + * block never to be reached. ETHER_NEW and ETHER_IFCHG have been added to that list. + */ + if (event & ~(ACTIVITY_NEW | IP_NEW | FLIPFLOP | FLIPFLOP_DECNET | IP_ETHER_REUSE | ETHER_NEW | ETHER_IFCHG)) { + /* New ether address */ + e2 = ap->elist[0]->e; + t2 = ap->elist[0]->t; + event |= IP_ETHERCHG; + /* Make room at head of list */ + alist_alloc(ap); + len = ap->ecount * sizeof(ap->elist[0]); + BCOPY(&ap->elist[0], &ap->elist[1], len); + ap->elist[0] = elist_alloc(a, e, t, h, interface); + ++ap->ecount; + } + + pthread_mutex_unlock(&mtx_ainfo); + + report(event, a, e, e2, &t, &t2, interface, if2); + + if (if2 != NULL) + free(if2); + + return(1); +} + +static struct einfo * +einfo_find(register u_char *e) +{ + register int i; + + for (i=0; i < et_cnt; i++) { + if (MEMCMP(einfo_table[i].e, e, sizeof(einfo_table[i].e)) == 0) + return(&einfo_table[i]); + } + + return(NULL); } static struct ainfo * @@ -259,7 +328,7 @@ /* Allocate and initialize a elist struct */ static struct einfo * elist_alloc(register u_int32_t a, register u_char *e, register time_t t, - register char *h) + register char *h, register char *interface) { register struct einfo *ep; register u_int size; @@ -280,12 +349,16 @@ ep = elist++; --eleft; - BCOPY(e, ep->e, 6); + BCOPY(e, ep->e, sizeof(ep->e)); if (h == NULL && !initializing) h = getsname(a); if (h != NULL && !isdigit((int)*h)) - strcpy(ep->h, h); + strncpy(ep->h, h, sizeof(ep->h)); ep->t = t; + + if (interface != NULL) + strncpy(ep->iface, interface, sizeof(ep->iface)); + return (ep); } @@ -304,7 +377,7 @@ if (!isdigit((int)*h) && strcmp(h, ep->h) != 0) { syslog(LOG_INFO, "hostname changed %s %s %s -> %s", intoa(ap->a), e2str(ep->e), ep->h, h); - strcpy(ep->h, h); + strncpy(ep->h, h, sizeof(ep->h)); } }