freebsd-ports/net-mgmt/arpwatch-devel/files/patch-ai
Kirill Ponomarev 486518fcaa This is a development fork of arpwatch. This has been
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
2004-01-19 23:34:48 +00:00

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));
}
}