ports/57019: [PATCH] arpwatch enhancements

Matthew George mdg at secureworks.net
Fri Sep 19 19:50:26 UTC 2003


>Number:         57019
>Category:       ports
>Synopsis:       [PATCH] arpwatch enhancements
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Fri Sep 19 12:50:22 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     mdg
>Release:        FreeBSD 5.1-RELEASE i386
>Organization:
SecureWorks
>Environment:
System: FreeBSD mdg.secureworks.net 5.1-RELEASE FreeBSD 5.1-RELEASE #2: Tue Jun 10 11:13:46 EDT 2003 mdg at mdg.secureworks.net:/usr/src/sys/i386/compile/GENERIC i386


>Description:

	see http://www.secureworks.com/open/?p=ArpWatch for more info

	Here is the description from there, but as these changes are rather significant, it may be better to treat this as a new port ... it's up to you guys, just let me know what you want to do with it.

	Several strcpy()'s changed to strncpy()'s, hardcoded sizes to sizeof()'s

	Multiple interface support

	    * struct einfo extended to include 10-byte interface name
	    * einfo_table, implemented as an array of HASHSIZE elements
	    * new function: struct einfo * einfo_find (u_char *e), searches einfo_table and returns pointer if it finds something or NULL
	    * ent_add(), elist_alloc() extended to include char *interface as an argument
	    * report() extended to take two interface args: current and old

	Event processing

	    * two new events: "new ethernet device", and "ethernet device changed interfaces"
	    * new enum evt_type sets up events as a bitfield. currently using ETHER_NEW, ETHER_IFCHG, ACTIVITY_NEW, IP_NEW, IP_ETHERCHG, IP_ETHER_REUSE, FLIPFLOP, and FLIPFLOP_DECNET. ent_add() and report() have been modified to use this properly.
	    * events are now aggregated. instead of sending an email for each condition, a single email is generated with the subject "Arpwatch Event ()" that contains a list of events and relevant information in thebody of the message.

	Threading

	The threading was done with pthread, not libthr / kse. The handler that gets called for execution is int pcap_thread(char *interface). The contents of this function are all the pcap operations pulled from main().

	Once the number of interfaces is determined, an array is created to store the thread id and associated interface (struct aw_threads). A thread is then created for each interface. When pcap_loop() is called and a packet is given to process_[ether|fddi] to deal with, the processing function looks up its current thread id, finds its record in the aw_threads array, and passes its interface from there with the other data it has to ent_add().

	By default, if -i is not specified, arpwatch will pcap_open_live() all non-loopback interfaces. More than one -i can not be specified. This was a bug before I started, and not one that I really care about fixing ;-).

	Two mutexes are provided for locking data during processing. Both are used in ent_add(): one for einfo_table access and one for ainfo_table access. In addition to enabling the multiple interface support, an added advantage of having the app threaded is (of course) not being required to use a separate process for each interface. Since threads share the same virtual memory space, the memory footprint is lower. The threshold seems to be about three interfaces. On a machine with eight interfaces, the single threaded process uses 34% of the total memory used by eight individual processes (not that it's much in either case, but still).

	ether.dat

	arp.dat : IP addresses :: ether.dat : MAC addresses

	A zero byte file is good enough to get started with. Unlike arp.dat, this file is not human-readable.

	    * ETHERFILE #define added to arpwatch.h
	    * -e command line option added, usage() modified
	          o note: There is a pre-existing bug for -f and -e with relative pathnames if ARPDIR exists but doesn't contain ARPFILE or ETHERFILE
	    * empty file created at same time as arp.dat
	    * support has been added for loading via readdata() and dumping via dump()

>How-To-Repeat:
	<code/input/activities to reproduce the problem (multiple lines)>
>Fix:

This has been tested on both 5.1-RELEASE and RELENG_4_8

diff -ru /usr/ports/net/arpwatch/Makefile ./Makefile
--- /usr/ports/net/arpwatch/Makefile	Sat Apr 19 19:44:22 2003
+++ ./Makefile	Mon Sep 15 17:57:41 2003
@@ -7,7 +7,7 @@

 PORTNAME=	arpwatch
 PORTVERSION=	2.1.a11
-PORTREVISION=	2
+PORTREVISION=	3
 CATEGORIES=	net
 MASTER_SITES=	http://www.Awfulhak.org/arpwatch/ \
 		ftp://ftp.ee.lbl.gov/
@@ -30,6 +30,8 @@
 	fi
 	${TOUCH} ${PREFIX}/arpwatch/arp.dat
 	${CHMOD} 644 ${PREFIX}/arpwatch/arp.dat
+	${TOUCH} ${PREFIX}/arpwatch/ether.dat
+	${CHMOD} 644 ${PREFIX}/arpwatch/ether.dat
 	for file in ethercodes.dat d.awk e.awk p.awk; do		\
 		${INSTALL_DATA} ${WRKSRC}/$$file ${PREFIX}/arpwatch/.;	\
 	done
diff -ru /usr/ports/net/arpwatch/files/arpwatch.sh ./files/arpwatch.sh
--- /usr/ports/net/arpwatch/files/arpwatch.sh	Thu Mar 14 05:03:11 2002
+++ ./files/arpwatch.sh	Mon Sep 15 17:46:22 2003
@@ -27,10 +27,18 @@
 		fi
 	fi

+	if [ ! -e "$PREFIX"/arpwatch/ether.dat ]; then
+		if [ -e "$PREFIX"/arpwatch/ether.dat- ]; then
+			cp "$PREFIX"/arpwatch/ether.dat- "$PREFIX"/arpwatch/ether.dat
+		else
+			touch "$PREFIX"/arpwatch/ether.dat
+		fi
+	fi
+
 	case ${arpwatch_interfaces} in
 	'')
 		if [ -x "$PREFIX"/sbin/arpwatch -a -d "$PREFIX"/arpwatch ]; then
-			"$PREFIX"/sbin/arpwatch && echo -n ' arpwatch'
+			"$PREFIX"/sbin/arpwatch ${arpwatch_flags} && echo -n ' arpwatch'
 		fi
 		;;
 	*)
diff -ru /usr/ports/net/arpwatch/files/patch-ab ./files/patch-ab
--- /usr/ports/net/arpwatch/files/patch-ab	Fri Aug 21 14:09:19 1998
+++ ./files/patch-ab	Mon Sep 15 14:40:36 2003
@@ -1,15 +1,15 @@
---- Makefile.in.orig	Wed Jul 29 06:16:45 1998
-+++ Makefile.in	Fri Aug 21 10:57:51 1998
-@@ -44,7 +44,7 @@
- CC = @CC@
+--- ../arpwatch.orig/Makefile.in	Wed Jun 14 20:39:55 2000
++++ ./Makefile.in	Mon Sep 15 14:31:33 2003
+@@ -45,7 +45,7 @@
+ PROG = arpwatch
  CCOPT = @V_CCOPT@
  INCLS = -I. @V_INCLS@
 -DEFS = -DDEBUG @DEFS@ -DARPDIR=\"$(ARPDIR)\" -DPATH_SENDMAIL=\"$(SENDMAIL)\"
-+DEFS = @DEFS@ -DARPDIR=\"$(ARPDIR)\" -DPATH_SENDMAIL=\"$(SENDMAIL)\"
++DEFS = @DEFS@ -pthread -DARPDIR=\"$(ARPDIR)\" -DPATH_SENDMAIL=\"$(SENDMAIL)\"

  # Standard CFLAGS
  CFLAGS = $(CCOPT) $(DEFS) $(INCLS)
-@@ -109,8 +109,8 @@
+@@ -110,8 +110,8 @@
  	$(CC) $(CFLAGS) -o $@ zap.o intoa.o -lutil

  install: force
diff -ru /usr/ports/net/arpwatch/files/patch-ae ./files/patch-ae
--- /usr/ports/net/arpwatch/files/patch-ae	Tue Nov 21 17:11:43 2000
+++ ./files/patch-ae	Mon Sep 15 14:50:26 2003
@@ -1,5 +1,5 @@
---- configure.orig	Thu Jun 15 01:37:53 2000
-+++ configure	Tue Sep  5 02:57:33 2000
+--- ../arpwatch.orig/configure	Wed May 16 14:26:11 2001
++++ ./configure	Wed Sep 10 13:08:05 2003
 @@ -649,7 +649,7 @@
    :
  fi
@@ -9,7 +9,7 @@
      V_INCLS=""
      if test "${srcdir}" != "." ; then
  	    V_INCLS="-I\$\(srcdir\)"
-@@ -2599,7 +2599,7 @@
+@@ -2496,7 +2496,7 @@
  		    fi
  		    V_CCOPT="$V_CCOPT -Wall"
  		    if test $ac_cv_lbl_gcc_vers -gt 1 ; then
@@ -18,3 +18,15 @@
  		    fi
  	    fi
      else
+@@ -3075,6 +3075,11 @@
+ if test ! -f arp.dat ; then
+ 	echo 'creating empty arp.dat file'
+ 	touch arp.dat
++fi
++
++if test ! -f ether.dat ; then
++	echo 'creating empty ether.dat file'
++	touch ether.dat
+ fi
+
+ if test -f .devel ; then
diff -ru /usr/ports/net/arpwatch/files/patch-ag ./files/patch-ag
--- /usr/ports/net/arpwatch/files/patch-ag	Thu Feb 22 17:56:40 2001
+++ ./files/patch-ag	Mon Sep 15 14:48:06 2003
@@ -1,6 +1,14 @@
---- arpwatch.c.orig	Thu Feb 22 22:47:29 2001
-+++ arpwatch.c	Thu Feb 22 22:47:29 2001
-@@ -107,6 +107,8 @@
+--- ../arpwatch.orig/arpwatch.c	Fri Oct 13 22:07:35 2000
++++ ./arpwatch.c	Mon Sep 15 14:45:56 2003
+@@ -36,6 +36,7 @@
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <sys/time.h>
++#include <pthread.h>
+
+ #if __STDC__
+ struct mbuf;
+@@ -107,6 +108,8 @@

  char *prog;

@@ -9,16 +17,64 @@
  int can_checkpoint;
  int swapped;
  int nobogons;
-@@ -170,7 +172,7 @@
- 	interface = NULL;
+@@ -123,6 +126,14 @@
+ static int nets_ind;
+ static int nets_size;
+
++struct aw_threads {
++  char *interface;
++  pthread_t thread;
++};
++
++struct aw_threads *threads = NULL;
++extern pthread_mutex_t mtx_einfo, mtx_ainfo;
++
+ extern int optind;
+ extern int opterr;
+ extern char *optarg;
+@@ -145,14 +156,14 @@
+ main(int argc, char **argv)
+ {
+ 	register char *cp;
+-	register int op, pid, snaplen, timeout, linktype, status;
++	register int op, pid, if_cnt, i;
+ #ifdef TIOCNOTTY
+ 	register int fd;
+ #endif
+-	register pcap_t *pd;
+-	register char *interface, *rfilename;
+-	struct bpf_program code;
++	register char *rfilename;
+ 	char errbuf[PCAP_ERRBUF_SIZE];
++	pcap_if_t *adp, *alldevsp = NULL;
++	char *interface = NULL;
+
+ 	if (argv[0] == NULL)
+ 		prog = "arpwatch";
+@@ -167,10 +178,8 @@
+ 	}
+
+ 	opterr = 0;
+-	interface = NULL;
  	rfilename = NULL;
- 	pd = NULL;
+-	pd = NULL;
 -	while ((op = getopt(argc, argv, "df:i:n:Nr:")) != EOF)
-+	while ((op = getopt(argc, argv, "df:i:m:n:Nr:")) != EOF)
++	while ((op = getopt(argc, argv, "de:f:i:m:n:Nr:")) != EOF)
  		switch (op) {

  		case 'd':
-@@ -202,6 +204,10 @@
+@@ -181,6 +190,10 @@
+ #endif
+ 			break;
+
++		case 'e':
++		        etherfile = optarg;
++			break;
++
+ 		case 'f':
+ 			arpfile = optarg;
+ 			break;
+@@ -202,6 +215,10 @@
  			rfilename = optarg;
  			break;

@@ -29,11 +85,223 @@
  		default:
  			usage();
  		}
-@@ -751,6 +757,6 @@
+@@ -213,19 +230,23 @@
+ 		net = 0;
+ 		netmask = 0;
+ 	} else {
+-		/* Determine interface if not specified */
+-		if (interface == NULL &&
+-		    (interface = pcap_lookupdev(errbuf)) == NULL) {
+-			(void)fprintf(stderr, "%s: lookup_device: %s\n",
+-			    prog, errbuf);
+-			exit(1);
+-		}
++		/* if not specified, do all non loopback interfaces */
++	        if (interface == NULL) {
+
+-		/* Determine network and netmask */
+-		if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) {
+-			(void)fprintf(stderr, "%s: bad interface %s: %s\n",
+-			    prog, interface, errbuf);
+-			exit(1);
++		  pcap_findalldevs(&alldevsp, errbuf);
++		  if (alldevsp == NULL) {
++		    (void)fprintf(stderr, "no suitable interfaces\n");
++		    exit(1);
++		  }
++
++		  if_cnt = 0;
++		  for(adp = alldevsp; adp != NULL; adp = adp->next) {
++		    if (adp->flags != PCAP_IF_LOOPBACK)
++		      ++if_cnt;
++		  }
++
++		} else {
++		  if_cnt = 1;
+ 		}
+
+ 		/* Drop into the background if not debugging */
+@@ -251,12 +272,82 @@
+ 		}
+ 	}
+
+-	openlog(prog, 0, LOG_DAEMON);
++	if (debug)
++	  openlog(prog, LOG_PERROR, LOG_DAEMON);
++	else
++	  openlog(prog, 0, LOG_DAEMON);
+
+ 	if (chdir(arpdir) < 0) {
+ 		syslog(LOG_ERR, "chdir(%s): %m", arpdir);
+ 		syslog(LOG_ERR, "(using current working directory)");
+ 	}
++	/* Read in database */
++	initializing = 1;
++	if (!readdata())
++		exit(1);
++	sorteinfo();
++#ifdef DEBUG
++	if (debug > 2) {
++		debugdump();
++		exit(0);
++	}
++#endif
++	initializing = 0;
++
++	(void)setsignal(SIGINT, die);
++	(void)setsignal(SIGTERM, die);
++	(void)setsignal(SIGHUP, die);
++	if (rfilename == NULL) {
++		(void)setsignal(SIGQUIT, checkpoint);
++		(void)setsignal(SIGALRM, checkpoint);
++		(void)alarm(CHECKPOINT);
++	}
++
++	threads = (struct aw_threads *) malloc(sizeof(struct aw_threads) * (if_cnt + 1));
++	memset((char *)threads, 0, sizeof(*threads) * (if_cnt + 1));
++	pthread_mutex_init(&mtx_einfo, NULL);
++	pthread_mutex_init(&mtx_ainfo, NULL);
++
++	if (interface != NULL)
++	  {
++	    threads[0].interface = interface;
++	    pthread_create(&threads[0].thread, NULL, (void *)pcap_thread, interface);
++	  }
++	else
++	  {
++	    i = 0;
++
++	    for (adp = alldevsp; adp != NULL; adp = adp->next)
++	      if (adp->flags != PCAP_IF_LOOPBACK)
++		{
++		  threads[i].interface = adp->name;
++		  pthread_create(&threads[i++].thread, NULL, (void *)pcap_thread, adp->name);
++		}
++	  }
++
++	for (i=0; i < if_cnt; i++)
++	  pthread_join(threads[i].thread, NULL);
++
++	if (!dump())
++		exit(1);
++	exit(0);
++}
++
++int
++pcap_thread(char *interface)
++{
++	register char *rfilename = NULL;
++	char errbuf[PCAP_ERRBUF_SIZE];
++	register pcap_t *pd = NULL;
++	register int snaplen, timeout, linktype, status;
++	struct bpf_program code;
++
++        /* Determine network and netmask */
++        if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) {
++	  (void)fprintf(stderr, "%s: bad interface %s: %s\n",
++			prog, interface, errbuf);
++	  return(1);
++	}
+
+ 	if (rfilename != NULL) {
+ 		pd = pcap_open_offline(rfilename, errbuf);
+@@ -306,27 +397,7 @@
+ 	if (rfilename == NULL)
+ 		syslog(LOG_INFO, "listening on %s", interface);
+
+-	/* Read in database */
+-	initializing = 1;
+-	if (!readdata())
+-		exit(1);
+-	sorteinfo();
+-#ifdef DEBUG
+-	if (debug > 2) {
+-		debugdump();
+-		exit(0);
+-	}
+-#endif
+-	initializing = 0;
+
+-	(void)setsignal(SIGINT, die);
+-	(void)setsignal(SIGTERM, die);
+-	(void)setsignal(SIGHUP, die);
+-	if (rfilename == NULL) {
+-		(void)setsignal(SIGQUIT, checkpoint);
+-		(void)setsignal(SIGALRM, checkpoint);
+-		(void)alarm(CHECKPOINT);
+-	}
+
+ 	switch (linktype) {
+
+@@ -347,9 +418,7 @@
+ 		exit(1);
+ 	}
+ 	pcap_close(pd);
+-	if (!dump())
+-		exit(1);
+-	exit(0);
++	return(0);
+ }
+
+ /* Process an ethernet arp/rarp packet */
+@@ -362,6 +431,8 @@
+ 	register u_char *sea, *sha;
+ 	register time_t t;
+ 	u_int32_t sia;
++	register pthread_t thread_self = NULL;
++	register struct aw_threads *atp = threads;
+
+ 	eh = (struct ether_header *)p;
+ 	ea = (struct ether_arp *)(eh + 1);
+@@ -400,9 +471,16 @@
+ 	/* Got a live one */
+ 	t = h->ts.tv_sec;
+ 	can_checkpoint = 0;
+-	if (!ent_add(sia, sea, t, NULL))
++	thread_self = pthread_self();
++
++       	for (atp = threads; atp != NULL; atp++)
++	  if (pthread_equal(atp->thread, thread_self))
++	    break;
++
++	if (!ent_add(sia, sea, t, NULL, atp->interface))
+ 		syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed",
+ 		    intoa(sia), e2str(sea), t);
++
+ 	can_checkpoint = 1;
+ }
+
+@@ -507,6 +585,8 @@
+ 	register u_char *sea, *sha;
+ 	register time_t t;
+ 	u_int32_t sia;
++	register pthread_t thread_self = NULL;
++	register struct aw_threads *atp = threads;
+
+ 	fh = (struct fddi_header *)p;
+ 	ea = (struct ether_arp *)(fh + 1);
+@@ -549,7 +629,13 @@
+ 	/* Got a live one */
+ 	t = h->ts.tv_sec;
+ 	can_checkpoint = 0;
+-	if (!ent_add(sia, sea, t, NULL))
++	thread_self = pthread_self();
++
++       	for (atp = threads; atp != NULL; atp++)
++	  if (atp->thread == thread_self)
++	    break;
++
++	if (!ent_add(sia, sea, t, NULL, atp->interface))
+ 		syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed",
+ 		    intoa(sia), e2str(sea), t);
+ 	can_checkpoint = 1;
+@@ -750,7 +836,7 @@
+ 	extern char version[];

  	(void)fprintf(stderr, "Version %s\n", version);
- 	(void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface]"
+-	(void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface]"
 -	    " [-n net[/width]] [-r file]\n", prog);
++	(void)fprintf(stderr, "usage: %s [-dN] [-f arpfile] [-e etherfile] [-i interface]"
 +	    " [-m email] [-n net[/width]] [-r file]\n", prog);
  	exit(1);
  }
diff -ru /usr/ports/net/arpwatch/files/patch-ah ./files/patch-ah
--- /usr/ports/net/arpwatch/files/patch-ah	Thu May 16 06:40:50 2002
+++ ./files/patch-ah	Mon Sep 15 15:02:03 2003
@@ -1,5 +1,5 @@
---- report.c.orig	Sun Oct  1 00:41:10 2000
-+++ report.c	Thu May 16 11:34:33 2002
+--- ../arpwatch.orig/report.c	Sat Sep 30 19:41:10 2000
++++ ./report.c	Fri Sep 12 18:57:04 2003
 @@ -45,6 +45,8 @@

  #include <ctype.h>
@@ -18,7 +18,18 @@
  static int cdepth;	/* number of outstanding children */

  static char *fmtdate(time_t);
-@@ -240,7 +244,7 @@
+@@ -232,15 +236,16 @@
+ }
+
+ void
+-report(register char *title, register u_int32_t a, register u_char *e1,
+-    register u_char *e2, register time_t *t1p, register time_t *t2p)
++report(evt_type event, register u_int32_t a, register u_char *e1,
++    register u_char *e2, register time_t *t1p, register time_t *t2p,
++    register char *interface, register char *old_interface)
+ {
+ 	register char *cp, *hn;
+ 	register int fd, pid;
  	register FILE *f;
  	char tempfile[64], cpu[64], os[64];
  	char *fmt = "%20s: %s\n";
@@ -27,7 +38,67 @@
  	char *watchee = WATCHEE;
  	char *sendmail = PATH_SENDMAIL;
  	char *unknown = "<unknown>";
-@@ -344,6 +348,25 @@
+@@ -251,9 +256,15 @@
+ 	if (initializing)
+ 		return;
+
++	/* these types are sent to syslog instead of reported on.
++	 * only continue if there are other events as well
++	 */
++	if (event == NULL || (event & ~(IP_ETHER_REUSE | FLIPFLOP_DECNET) == 0))
++	  return;
++
+ 	if (debug) {
+ 		if (debug > 1) {
+-			dosyslog(LOG_NOTICE, title, a, e1, e2);
++			dosyslog(LOG_NOTICE, "event", a, e1, e2);
+ 			return;
+ 		}
+ 		f = stdout;
+@@ -270,7 +281,7 @@
+ 		}
+
+ 		/* Syslog this event too */
+-		dosyslog(LOG_NOTICE, title, a, e1, e2);
++		dosyslog(LOG_NOTICE, "event", a, e1, e2);
+
+ 		/* Update child depth */
+ 		++cdepth;
+@@ -304,12 +315,31 @@
+ 	(void)fprintf(f, "To: %s\n", watcher);
+ 	hn = gethname(a);
+ 	if (!isdigit(*hn))
+-		(void)fprintf(f, "Subject: %s (%s)\n", title, hn);
++		(void)fprintf(f, "Subject: Arpwatch Event (%s)\n", hn);
+ 	else {
+-		(void)fprintf(f, "Subject: %s\n", title);
++		(void)fprintf(f, "Subject: Arpwatch Event\n");
+ 		hn = unknown;
+ 	}
+ 	(void)putc('\n', f);
++
++	if (event & ETHER_NEW)
++	  (void)fprintf(f, fmt, "event", "new ethernet device");
++	if (event & ETHER_IFCHG)
++	  (void)fprintf(f, fmt, "event", "ethernet device changed interfaces");
++	if (event & ACTIVITY_NEW)
++	  (void)fprintf(f, fmt, "event", "new activity");
++	if (event & IP_NEW)
++	  (void)fprintf(f, fmt, "event", "new active IP address");
++	if (event & IP_ETHERCHG)
++	  (void)fprintf(f, fmt, "event", "IP changed ethernet address");
++	if (event & FLIPFLOP)
++	  (void)fprintf(f, fmt, "event", "flip flop");
++
++	(void)fprintf(f, fmt, "interface", interface);
++
++	if (old_interface != NULL)
++	  (void)fprintf(f, fmt, "old interface", old_interface);
++
+ 	(void)fprintf(f, fmt, "hostname", hn);
+ 	(void)fprintf(f, fmt, "ip address", intoa(a));
+ 	(void)fprintf(f, fmt, "ethernet address", e2str(e1));
+@@ -344,6 +374,25 @@
  		exit(1);
  	}
  	/* XXX Need to freopen()? */
diff -ru /usr/ports/net/arpwatch/files/patch-ai ./files/patch-ai
--- /usr/ports/net/arpwatch/files/patch-ai	Thu Feb 22 17:56:40 2001
+++ ./files/patch-ai	Mon Sep 15 14:43:13 2003
@@ -1,6 +1,12 @@
---- arpsnmp.c.orig	Mon Jan 18 01:47:40 1999
-+++ arpsnmp.c	Thu Feb 22 22:47:29 2001
-@@ -68,6 +68,8 @@
+--- ../arpwatch.orig/arpsnmp.c	Sun Jan 17 20:47:40 1999
++++ ./arpsnmp.c	Mon Sep 15 14:31:33 2003
+@@ -63,14 +63,17 @@
+ /* Forwards */
+ int	main(int, char **);
+ int	readsnmp(char *);
+-int	snmp_add(u_int32_t, u_char *, time_t, char *);
++int	snmp_add(u_int32_t, u_char *, time_t, char *, char *);
+ __dead	void usage(void) __attribute__((volatile));

  char *prog;

@@ -9,7 +15,11 @@
  extern int optind;
  extern int opterr;
  extern char *optarg;
-@@ -90,7 +92,7 @@
++char *interface = NULL;
+
+ int
+ main(int argc, char **argv)
+@@ -90,7 +93,7 @@
  	}

  	opterr = 0;
@@ -18,7 +28,7 @@
  		switch (op) {

  		case 'd':
-@@ -105,6 +107,10 @@
+@@ -105,6 +108,10 @@
  			arpfile = optarg;
  			break;

@@ -29,7 +39,25 @@
  		default:
  			usage();
  		}
-@@ -184,6 +190,6 @@
+@@ -138,7 +145,7 @@
+ static time_t now;
+
+ int
+-snmp_add(register u_int32_t a, register u_char *e, time_t t, register char *h)
++snmp_add(register u_int32_t a, register u_char *e, time_t t, register char *h, register char *i)
+ {
+ 	/* Watch for ethernet broadcast */
+ 	if (MEMCMP(e, zero, 6) == 0 || MEMCMP(e, allones, 6) == 0) {
+@@ -153,7 +160,7 @@
+ 	}
+
+ 	/* Use current time (although it would be nice to subtract idle time) */
+-	return (ent_add(a, e, now, h));
++	return (ent_add(a, e, now, h, interface));
+ }
+
+ /* Process an snmp file */
+@@ -184,6 +191,6 @@

  	(void)fprintf(stderr, "Version %s\n", version);
  	(void)fprintf(stderr,
diff -ru /usr/ports/net/arpwatch/files/patch-aj ./files/patch-aj
--- /usr/ports/net/arpwatch/files/patch-aj	Thu Feb 22 17:56:40 2001
+++ ./files/patch-aj	Mon Sep 15 17:31:56 2003
@@ -1,6 +1,18 @@
---- arpwatch.8.orig	Sun Oct  8 21:31:28 2000
-+++ arpwatch.8	Thu Feb 22 22:47:29 2001
-@@ -38,6 +38,9 @@
+--- ../arpwatch-2.1a11/arpwatch.8	Sun Oct  8 16:31:28 2000
++++ ./arpwatch.8	Mon Sep 15 17:30:45 2003
+@@ -30,7 +30,10 @@
+ .B -dN
+ ] [
+ .B -f
+-.I datafile
++.I arpfile
++] [
++.B -e
++.I etherfile
+ ] [
+ .B -i
+ .I interface
+@@ -38,6 +41,9 @@
  .br
  .ti +8
  [
@@ -10,10 +22,23 @@
  .B -n
  .IR net [/ width
  ]] [
-@@ -69,6 +72,12 @@
+@@ -67,8 +73,24 @@
+ .IR arp.dat .
+ .LP
  The
++.B -e
++flag is used to set the ethernet/interface database filename.
++The default is
++.IR ether.dat .
++.LP
++The
++.B -i
++flag is used to specify a single interface.  By default,
++.B arpwatch
++will listen to all non-loopback interfaces.  Using more than one
  .B -i
- flag is used to override the default interface.
+-flag is used to override the default interface.
++option on the same command line is not supported.
 +.LP
 +The
 +.B -m
@@ -23,3 +48,54 @@
  .LP
  The
  .B -n
+@@ -81,6 +103,8 @@
+ The
+ .B -N
+ flag disables reporting any bogons.
++It is highly recommended that this flag be used on machines with
++multiple interfaces.
+ .LP
+ The
+ .B -r
+@@ -96,6 +120,8 @@
+ .LP
+ Note that an empty
+ .I arp.dat
++and
++.I ether.dat
+ file must be created before the first time you run
+ .BR arpwatch .
+ .LP
+@@ -105,12 +131,19 @@
+ (and
+ .BR arpsnmp (1)):
+ .TP
++.B "new ethernet device"
++The ethernet address has not been seen before.
++.TP
++.B "ethernet device changed interfaces"
++An ethernet address associated with one interface has moved to a
++different interface.
++.TP
+ .B "new activity"
+ This ethernet/ip address pair has been used for the first time six
+ months or more.
+ .TP
+-.B "new station"
+-The ethernet address has not been seen before.
++.B "new active IP address"
++The IP address has not been seen before.
+ .TP
+ .B "flip flop"
+ The ethernet address has changed from the most recently seen address to
+@@ -152,8 +185,9 @@
+ .na
+ .nh
+ .nf
+-/usr/operator/arpwatch - default directory
++/usr/local/arpwatch - default directory
+ arp.dat - ethernet/ip address database
++ether.dat - ethernet/interface address database
+ ethercodes.dat - vendor ethernet block list
+ .ad
+ .hy


Additionally, these extra patch files are required:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	patch-al
#	patch-am
#	patch-an
#	patch-ao
#	patch-ap
#	patch-aq
#	patch-ar
#	patch-as
#	patch-at
#
echo x - patch-al
sed 's/^X//' >patch-al << 'END-of-patch-al'
X--- ../arpwatch-2.1a11/arpwatch.h	Sat Sep 30 19:40:55 2000
X+++ ./arpwatch.h	Fri Sep 12 17:01:42 2003
X@@ -1,6 +1,7 @@
X /* @(#) $Id: arpwatch.h,v 1.29 2000/09/30 23:40:49 leres Exp $ (LBL) */
X
X #define ARPFILE "arp.dat"
X+#define ETHERFILE "ether.dat"
X #define ETHERCODES "ethercodes.dat"
X #define CHECKPOINT (15*60)		/* Checkpoint time in seconds */
X
X@@ -40,3 +41,5 @@
X #define SPA(ap) ((ap)->arp_spa)
X #define TPA(ap) ((ap)->arp_tpa)
X #endif
X+
X+int pcap_thread(char *);
END-of-patch-al
echo x - patch-am
sed 's/^X//' >patch-am << 'END-of-patch-am'
X--- ../arpwatch.orig/configure.in	Sat Oct 14 14:19:10 2000
X+++ ./configure.in	Wed Sep 10 13:08:05 2003
X@@ -170,6 +170,11 @@
X if test ! -f arp.dat ; then
X 	echo 'creating empty arp.dat file'
X 	touch arp.dat
X+fi
X+
X+if test ! -f ether.dat ; then
X+	echo 'creating empty ether.dat file'
X+	touch ether.dat
X fi
X
X if test -f .devel ; then
END-of-patch-am
echo x - patch-an
sed 's/^X//' >patch-an << 'END-of-patch-an'
X--- ../arpwatch.orig/db.c	Sat Sep 30 19:39:58 2000
X+++ ./db.c	Mon Sep 15 13:17:07 2003
X@@ -41,6 +41,7 @@
X #include <string.h>
X #include <syslog.h>
X #include <unistd.h>
X+#include <pthread.h>
X
X #include "gnuc.h"
X #ifdef HAVE_OS_PROTO_H
X@@ -54,18 +55,9 @@
X #include "report.h"
X #include "util.h"
X
X-#define HASHSIZE (2 << 15)
X-
X #define NEWACTIVITY_DELTA (6*30*24*60*60)	/* 6 months in seconds */
X #define FLIPFLIP_DELTA (24*60*60)		/* 24 hours in seconds */
X
X-/* Ethernet info */
X-struct einfo {
X-	u_char e[6];		/* ether address */
X-	char h[34];		/* simple hostname */
X-	time_t t;		/* timestamp */
X-};
X-
X /* Address info */
X struct ainfo {
X 	u_int32_t a;		/* ip address */
X@@ -78,22 +70,69 @@
X /* Address hash table */
X static struct ainfo ainfo_table[HASHSIZE];
X
X+
X+/* Ethernet hash table */
X+struct einfo einfo_table[HASHSIZE];
X+int et_cnt = 0;
X+
X static void alist_alloc(struct ainfo *);
X int cmpeinfo(const void *, const void *);
X-static struct einfo *elist_alloc(u_int32_t, u_char *, time_t, char *);
X+static struct einfo *elist_alloc(u_int32_t, u_char *, time_t, char *, char *);
X static struct ainfo *ainfo_find(u_int32_t);
X+static struct einfo *einfo_find(u_char *);
X static void check_hname(struct ainfo *);
X struct ainfo *newainfo(void);
X
X+pthread_mutex_t mtx_einfo, mtx_ainfo;
X+
X int
X-ent_add(register u_int32_t a, register u_char *e, time_t t, register char *h)
X+ent_add(register u_int32_t a, register u_char *e, time_t t, register char *h, register char *interface)
X {
X 	register struct ainfo *ap;
X-	register struct einfo *ep;
X+	struct einfo *ep;
X 	register int i;
X 	register u_int len;
X 	u_char *e2;
X 	time_t t2;
X+	register evt_type event = NULL;
X+	char *if2 = NULL;
X+
X+	pthread_mutex_lock(&mtx_einfo);
X+
X+	/* Lookup ethernet address */
X+	ep = einfo_find(e);
X+
X+	/* New einfo? (elist_alloc makes 16 at a time -- no thanks) */
X+	if (ep == NULL && ! initializing) {
X+		if (et_cnt >= HASHSIZE) {
X+			syslog(LOG_ERR, "ERROR: einfo_table too big");
X+		} else {
X+		  ep = &einfo_table[et_cnt++];
X+		  BCOPY(e, ep->e, sizeof(ep->e));
X+		  if (h == NULL)
X+		    h = getsname(a);
X+		  if (h != NULL && !isdigit((int)*h))
X+		    strncpy(ep->h, h, sizeof(ep->h));
X+		  ep->t = t;
X+		  strncpy(ep->iface, interface, sizeof(ep->iface));
X+		  event |= ETHER_NEW;
X+		  e2 = NULL;
X+		  t2 = NULL;
X+		}
X+	} else if (! initializing) {
X+		if (strncmp(ep->iface, interface, sizeof(ep->iface)) != 0) {
X+			event |= ETHER_IFCHG;
X+			asprintf(&if2, "%s", ep->iface);
X+			memset((char *)ep->iface, 0, sizeof(ep->iface));
X+			BCOPY(interface, ep->iface, sizeof(ep->iface));
X+			e2 = NULL;
X+			t2 = ep->t;
X+			ep->t = t;
X+		}
X+	}
X+
X+	pthread_mutex_unlock(&mtx_einfo);
X+	pthread_mutex_lock(&mtx_ainfo);
X
X 	/* Lookup ip address */
X 	ap = ainfo_find(a);
X@@ -101,28 +140,30 @@
X 	/* Check for the usual case first */
X 	if (ap->ecount > 0) {
X 		ep = ap->elist[0];
X-		if (MEMCMP(e, ep->e, 6) == 0) {
X+		if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) {
X 			if (t - ep->t > NEWACTIVITY_DELTA) {
X-				report("new activity", a, e, NULL, &t, &ep->t);
X+			        event |= ACTIVITY_NEW;
X+				e2 = NULL;
X+				t2 = ep->t;
X 				check_hname(ap);
X 			}
X 			ep->t = t;
X-			return (1);
X 		}
X 	}
X
X 	/* Check for a virgin ainfo record */
X 	if (ap->ecount == 0) {
X 		ap->ecount = 1;
X-		ap->elist[0] = elist_alloc(a, e, t, h);
X-		report("new station", a, e, NULL, &t, NULL);
X-		return (1);
X+		ap->elist[0] = elist_alloc(a, e, t, h, interface);
X+		event |= IP_NEW;
X+		e2 = NULL;
X+		t2 = NULL;
X 	}
X
X 	/* Check for a flip-flop */
X 	if (ap->ecount > 1) {
X 		ep = ap->elist[1];
X-		if (MEMCMP(e, ep->e, 6) == 0) {
X+		if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) {
X 			/*
X 			 * Suppress report when less than
X 			 * FLIPFLOP_DELTA and one of the two ethernet
X@@ -131,48 +172,76 @@
X 			t2 = ap->elist[0]->t;
X 			e2 = ap->elist[0]->e;
X 			if (t - t2 < FLIPFLIP_DELTA &&
X-			    (isdecnet(e) || isdecnet(e2)))
X+			    (isdecnet(e) || isdecnet(e2))) {
X 				dosyslog(LOG_INFO,
X 				    "suppressed DECnet flip flop", a, e, e2);
X-			else
X-				report("flip flop", a, e, e2, &t, &t2);
X+				event |= FLIPFLOP_DECNET;
X+			} else {
X+				event |= FLIPFLOP;
X+			}
X+
X 			ap->elist[1] = ap->elist[0];
X 			ap->elist[0] = ep;
X 			ep->t = t;
X 			check_hname(ap);
X-			return (1);
X 		}
X 	}
X
X 	for (i = 2; i < ap->ecount; ++i) {
X 		ep = ap->elist[i];
X-		if (MEMCMP(e, ep->e, 6) == 0) {
X+		if (MEMCMP(e, ep->e, sizeof(ep->e)) == 0) {
X 			/* An old entry comes to life */
X 			e2 = ap->elist[0]->e;
X 			t2 = ap->elist[0]->t;
X 			dosyslog(LOG_NOTICE, "reused old ethernet address",
X 			    a, e, e2);
X+			event |= IP_ETHER_REUSE;
X 			/* Shift entries down */
X 			len = i * sizeof(ap->elist[0]);
X 			BCOPY(&ap->elist[0], &ap->elist[1], len);
X 			ap->elist[0] = ep;
X 			ep->t = t;
X 			check_hname(ap);
X-			return (1);
X 		}
X 	}
X
X-	/* New ether address */
X-	e2 = ap->elist[0]->e;
X-	t2 = ap->elist[0]->t;
X-	report("changed ethernet address", a, e, e2, &t, &t2);
X-	/* Make room at head of list */
X-	alist_alloc(ap);
X-	len = ap->ecount * sizeof(ap->elist[0]);
X-	BCOPY(&ap->elist[0], &ap->elist[1], len);
X-	ap->elist[0] = elist_alloc(a, e, t, h);
X-	++ap->ecount;
X-	return (1);
X+	/* as originally written, any of these conditions would cause this
X+	 * block never to be reached. ETHER_NEW and ETHER_IFCHG have been added to that list.
X+	 */
X+	if (event & ~(ACTIVITY_NEW | IP_NEW | FLIPFLOP | FLIPFLOP_DECNET | IP_ETHER_REUSE | ETHER_NEW | ETHER_IFCHG)) {
X+	  /* New ether address */
X+	  e2 = ap->elist[0]->e;
X+	  t2 = ap->elist[0]->t;
X+	  event |= IP_ETHERCHG;
X+	  /* Make room at head of list */
X+	  alist_alloc(ap);
X+	  len = ap->ecount * sizeof(ap->elist[0]);
X+	  BCOPY(&ap->elist[0], &ap->elist[1], len);
X+	  ap->elist[0] = elist_alloc(a, e, t, h, interface);
X+	  ++ap->ecount;
X+	}
X+
X+	pthread_mutex_unlock(&mtx_ainfo);
X+
X+	report(event, a, e, e2, &t, &t2, interface, if2);
X+
X+	if (if2 != NULL)
X+	  free(if2);
X+
X+	return(1);
X+}
X+
X+static struct einfo *
X+einfo_find(register u_char *e)
X+{
X+	register int i;
X+
X+	for (i=0; i < et_cnt; i++) {
X+		if (MEMCMP(einfo_table[i].e, e, sizeof(einfo_table[i].e)) == 0)
X+			return(&einfo_table[i]);
X+	}
X+
X+	return(NULL);
X }
X
X static struct ainfo *
X@@ -259,7 +328,7 @@
X /* Allocate and initialize a elist struct */
X static struct einfo *
X elist_alloc(register u_int32_t a, register u_char *e, register time_t t,
X-    register char *h)
X+    register char *h, register char *interface)
X {
X 	register struct einfo *ep;
X 	register u_int size;
X@@ -280,12 +349,16 @@
X
X 	ep = elist++;
X 	--eleft;
X-	BCOPY(e, ep->e, 6);
X+	BCOPY(e, ep->e, sizeof(ep->e));
X 	if (h == NULL && !initializing)
X 		h = getsname(a);
X 	if (h != NULL && !isdigit((int)*h))
X-		strcpy(ep->h, h);
X+		strncpy(ep->h, h, sizeof(ep->h));
X 	ep->t = t;
X+
X+	if (interface != NULL)
X+	  strncpy(ep->iface, interface, sizeof(ep->iface));
X+
X 	return (ep);
X }
X
X@@ -304,7 +377,7 @@
X 	if (!isdigit((int)*h) && strcmp(h, ep->h) != 0) {
X 		syslog(LOG_INFO, "hostname changed %s %s %s -> %s",
X 		    intoa(ap->a), e2str(ep->e), ep->h, h);
X-		strcpy(ep->h, h);
X+		strncpy(ep->h, h, sizeof(ep->h));
X 	}
X }
X
END-of-patch-an
echo x - patch-ao
sed 's/^X//' >patch-ao << 'END-of-patch-ao'
X--- ../arpwatch.orig/db.h	Wed Jun  5 01:39:30 1996
X+++ ./db.h	Mon Sep 15 14:55:27 2003
X@@ -1,10 +1,21 @@
X /* @(#) $Header: db.h,v 1.8 96/06/04 22:39:29 leres Exp $ (LBL) */
X
X+#define HASHSIZE (2 << 15)
X+
X typedef void (*ent_process)(u_int32_t, u_char *, time_t, char *);
X
X #ifdef	DEBUG
X void	debugdump(void);
X #endif
X-int	ent_add(u_int32_t, u_char *, time_t, char *);
X+int	ent_add(u_int32_t, u_char *, time_t, char *, char *);
X int	ent_loop(ent_process);
X void	sorteinfo(void);
X+
X+/* Ethernet info */
X+struct einfo {
X+	u_char e[6];		/* ether address */
X+	char h[34];		/* simple hostname */
X+	time_t t;		/* timestamp */
X+	char iface[10];		/* interface name */
X+};
X+
END-of-patch-ao
echo x - patch-ap
sed 's/^X//' >patch-ap << 'END-of-patch-ap'
X--- ../arpwatch.orig/file.c	Fri Oct 13 18:29:43 2000
X+++ ./file.c	Fri Sep 12 17:01:42 2003
X@@ -20,7 +20,7 @@
X  */
X #ifndef lint
X static const char rcsid[] =
X-    "@(#) $Id: file.c,v 1.25 2000/10/13 22:29:42 leres Exp $ (LBL)";
X+    "@(#) $Id: file.c,v 1.2 2003/09/12 21:01:42 mdg Exp $ (LBL)";
X #endif
X
X /*
X@@ -130,7 +130,13 @@
X 			}
X 		}
X
X-		if (!(*fn)(a, e, t, h))
X+		/* NULL for the interface here is ok because we don't do
X+		 * anything in ent_add() for einfo when initializing,
X+		 * and the only time this code section is reached is
X+		 * during initialization (via readdata()).  snmp_add()
X+		 * is irrelevant, as no ether tracking has been added to it.
X+		 */
X+		if (!(*fn)(a, e, t, h, NULL))
X 			return(0);
X 	}
X
END-of-patch-ap
echo x - patch-aq
sed 's/^X//' >patch-aq << 'END-of-patch-aq'
X--- ../arpwatch.orig/file.h	Sun Jan 17 20:46:04 1999
X+++ ./file.h	Fri Sep 12 17:01:42 2003
X@@ -1,5 +1,5 @@
X /* @(#) $Header: file.h,v 1.4 99/01/17 17:46:03 leres Exp $ (LBL) */
X
X-typedef int (*file_process)(u_int32_t, u_char *, time_t, char *);
X+typedef int (*file_process)(u_int32_t, u_char *, time_t, char *, char *);
X
X int file_loop(FILE *, file_process, const char *);
END-of-patch-aq
echo x - patch-ar
sed 's/^X//' >patch-ar << 'END-of-patch-ar'
X--- ../arpwatch.orig/report.h	Wed Jun  5 01:40:54 1996
X+++ ./report.h	Mon Sep 15 15:03:20 2003
X@@ -1,3 +1,16 @@
X /* @(#) $Header: report.h,v 1.3 96/06/04 22:40:53 leres Exp $ (LBL) */
X
X-void report(char *, u_int32_t, u_char *, u_char *, time_t *, time_t *);
X+
X+typedef enum
X+  {
X+    ETHER_NEW=1,
X+    ETHER_IFCHG=2,
X+    ACTIVITY_NEW=4,
X+    IP_NEW=8,
X+    IP_ETHERCHG=16,
X+    IP_ETHER_REUSE=32,
X+    FLIPFLOP=64,
X+    FLIPFLOP_DECNET=128
X+  } evt_type;
X+
X+void report(evt_type, u_int32_t, u_char *, u_char *, time_t *, time_t *, char *, char *);
END-of-patch-ar
echo x - patch-as
sed 's/^X//' >patch-as << 'END-of-patch-as'
X--- ../arpwatch.orig/util.c	Fri Oct 13 18:49:03 2000
X+++ ./util.c	Wed Sep 10 13:03:27 2003
X@@ -53,6 +53,7 @@
X
X char *arpdir = ARPDIR;
X char *arpfile = ARPFILE;
X+char *etherfile = ETHERFILE;
X char *ethercodes = ETHERCODES;
X
X /* Broadcast ethernet addresses */
X@@ -105,7 +106,7 @@
X dump(void)
X {
X 	register int fd;
X-	char oldarpfile[256], newarpfile[256];
X+	char oldarpfile[256], newarpfile[256], *oldetherfile, *newetherfile;
X
X 	(void)sprintf(oldarpfile, "%s-", arpfile);
X 	(void)sprintf(newarpfile, "%s.new", arpfile);
X@@ -130,6 +131,32 @@
X 		syslog(LOG_ERR, "rename %s -> %s: %m", newarpfile, arpfile);
X 		return(0);
X 	}
X+
X+	/* ether info */
X+	(void)asprintf(&oldetherfile, "%s-", etherfile);
X+	(void)asprintf(&newetherfile, "%s.new", etherfile);
X+
X+	if ((fd = creat(newetherfile, 0644)) < 0) {
X+		syslog(LOG_ERR, "creat(%s): %m", newetherfile);
X+		return(0);
X+	}
X+	if ((dumpf = fdopen(fd, "w")) == NULL) {
X+		syslog(LOG_ERR, "fdopen(%s): %m", newetherfile);
X+		return(0);
X+	}
X+
X+	fwrite(einfo_table, sizeof(struct einfo), et_cnt, dumpf);
X+
X+	(void)fclose(dumpf);
X+	if (rename(etherfile, oldetherfile) < 0) {
X+		syslog(LOG_ERR, "rename %s -> %s: %m", etherfile, oldetherfile);
X+		return(0);
X+	}
X+	if (rename(newetherfile, etherfile) < 0) {
X+		syslog(LOG_ERR, "rename %s -> %s: %m", newetherfile, etherfile);
X+		return(0);
X+	}
X+
X 	return(1);
X }
X
X@@ -138,7 +165,9 @@
X readdata(void)
X {
X 	register FILE *f;
X+	char line[1024];
X
X+	/* arp.dat */
X 	if ((f = fopen(arpfile, "r")) == NULL) {
X 		syslog(LOG_ERR, "fopen(%s): %m", arpfile);
X 		return(0);
X@@ -147,6 +176,15 @@
X 		(void)fclose(f);
X 		return(0);
X 	}
X+	(void)fclose(f);
X+
X+	/* ether.dat */
X+	if ((f = fopen(etherfile, "r")) == NULL) {
X+	        syslog(LOG_ERR, "fopen(%s): %m", etherfile);
X+		return(0);
X+	}
X+
X+	et_cnt = fread(einfo_table, sizeof(struct einfo), HASHSIZE, f);
X 	(void)fclose(f);
X
X 	/* It's not fatal if we can't open the ethercodes file */
END-of-patch-as
echo x - patch-at
sed 's/^X//' >patch-at << 'END-of-patch-at'
X--- ../arpwatch.orig/util.h	Sun Oct  6 06:22:14 1996
X+++ ./util.h	Wed Sep 10 13:03:27 2003
X@@ -11,6 +11,9 @@
X extern char *arpfile;
X extern char *oldarpfile;
X extern char *ethercodes;
X+extern char *etherfile;
X+extern struct einfo einfo_table[];
X+extern int et_cnt;
X
X extern u_char zero[6];
X extern u_char allones[6];
END-of-patch-at
exit



-- 
Matthew George
SecureWorks Technical Operations

>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the freebsd-ports-bugs mailing list