--- arpwatch.c.orig	Sat Oct 14 04:07:35 2000
+++ arpwatch.c	Tue Jan 20 00:22:23 2004
@@ -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;
 
+char *Watcher = NULL;
+
 int can_checkpoint;
 int swapped;
 int nobogons;
@@ -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;
-	while ((op = getopt(argc, argv, "df:i:n:Nr:")) != EOF)
+	while ((op = getopt(argc, argv, "de:f:i:m:n:Nr:")) != EOF)
 		switch (op) {
 
 		case 'd':
@@ -181,6 +190,10 @@
 #endif
 			break;
 
+		case 'e':
+		        etherfile = optarg;
+			break;
+
 		case 'f':
 			arpfile = optarg;
 			break;
@@ -202,6 +215,10 @@
 			rfilename = optarg;
 			break;
 
+		case 'm':
+			Watcher = optarg;
+			break;
+
 		default:
 			usage();
 		}
@@ -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 */
@@ -238,7 +259,7 @@
 				exit(0);
 			(void)close(fileno(stdin));
 			(void)close(fileno(stdout));
-			(void)close(fileno(stderr));
+
 #ifdef TIOCNOTTY
 			fd = open("/dev/tty", O_RDWR);
 			if (fd >= 0) {
@@ -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]"
-	    " [-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);
 }
