486518fcaa
threaded in order to better deal with the requirements of multi-interface routers. Information regarding MAC addresses and interfaces is maintained by the program, and an alert is issued should a device move between interfaces. In addition, event processing has been refactored, and some bugs have been fixed. PR: 59180 Submitted by: Matthew George <mdg@secureworks.net> Approved by: portmgr
271 lines
6.8 KiB
Text
271 lines
6.8 KiB
Text
--- ../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 <string.h>
|
|
#include <syslog.h>
|
|
#include <unistd.h>
|
|
+#include <pthread.h>
|
|
|
|
#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));
|
|
}
|
|
}
|
|
|