Index: 031204/preproc_plugins/macwatch.c
===================================================================
--- 031204/preproc_plugins/macwatch.c	(revision 5)
+++ 031204/preproc_plugins/macwatch.c	(working copy)
@@ -9,7 +9,6 @@
  * o Gratuitous arp detection
  * o ARP sweep detection?
  * o Unicast request detection
- * o Saving of tuple database in between restarts
  * o RARP and other arp type support?
  * o Alert on replies with no requests
  * o IP handler
@@ -25,10 +24,16 @@
  * o IPX, 8 byte protocol address 
  * o Improved hash function (upgraded to 1a)
  * o hln/pln matching bug (could match on a portion of a larger h/paddr)
+ * o Saving of tuple database in between restarts
 */
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
 
 #include <firestorm.h>
 #include <packet.h>
@@ -48,6 +53,8 @@
 #define MAX_HLN 	6
 #define ARP_PKT_SIZE 	8
 
+#define DBFILENAME	"macwatchdb"
+
 /* The macwatch address struct */
 struct arpaddr {
 
@@ -130,10 +137,17 @@
 	addrhash[hashval]=mwn;
 
 	/* Alert accordingly */
-	if (tuple_count)
+	if (tuple_count) {
 		alert(&alert_mw_dupha,pkt);
-	else
+#ifdef DEBUG
+		mesg(M_DEBUG,"macwatch: duplicate");
+#endif
+	} else {
 		alert(&alert_mw_newpa,pkt);
+#ifdef DEBUG
+		mesg(M_DEBUG,"macwatch: new");
+#endif
+	}
 }		
 
 /* Pre-process arp packets */
@@ -173,27 +187,77 @@
 
 static void macwatch_free(void *priv)
 {
-	int i,hashes=0,ips=0;
+	unsigned int i,hashes=0,ips=0;
 	struct arpaddr *mw,*mwp;
+	int fd;
+
+	/* Write tuples to disk (we're in root_dir) */
+	if ( (fd = open(DBFILENAME, O_WRONLY|O_CREAT|O_TRUNC, 00640)) < 0 ) {
+		mesg(M_ERR,"macwatch: %s: open(): %s", DBFILENAME, strerror(errno));
+	}
 	
 	for (i=0;i<MW_ADDR_HASH_SIZE;i++) 
 		if (addrhash[i]!=NULL) {
 			hashes++;
-			for (mw=addrhash[i]; mw!=NULL; ) {
-				ips++;
-				mwp=mw;
-				mw=mw->next;
+			for (mw = addrhash[i]; mw != NULL; ) {
+				if (fd >= 0) { 
+					write(fd, mw, sizeof(struct arpaddr));
+				}
+				ips ++;
+				mwp = mw;
+				mw = mw->next;
 				free(mwp);
 			}
 		}
+
+	if (fd >= 0) {
+		if (close(fd) < 0 ) {
+			mesg(M_ERR, "macwatch: %s: close(): %s", DBFILENAME, strerror(errno));
+		} else {
+			mesg(M_INFO, "macwatch: wrote %i tuples to %s", ips, DBFILENAME);
+		};
+	}
 	return;
 };
 
 static int macwatch_init(char *args)
 {
-	int err=0;
+	int err=0,fd;
+	unsigned int ips=0;
+	ssize_t bytes;
+	struct arpaddr mw, *pmw;
+	u_int32_t hashval;
+	
 	err += preproc_activate("arp", macwatch_arpwatcher, macwatch_free, NULL);
 	/* Appletalk arp (aarp)?  IPX Arp? */
+
+	/* Read tuples from disk */
+	if ( (fd = open(DBFILENAME, O_RDONLY)) < 0) {
+		mesg(M_ERR,"macwatch: %s: open(): %s", DBFILENAME, strerror(errno));
+	} else {
+		while ( (bytes = read(fd, &mw, sizeof(struct arpaddr))) == sizeof(struct arpaddr) ) {
+			if ( (mw.hln > MAX_HLN) || (mw.pln > MAX_PLN)) {
+				mesg(M_WARN,"macwatch: corrupted tuple found in %s", DBFILENAME);
+				continue;
+			}
+			hashval = skunk_hash((u_int8_t *)&mw.paddr, mw.pln) & MW_ADDR_HASH_MASK;
+			/* endianness of hrd and proto are already network order */
+			mw.next = addrhash[hashval];
+			pmw = malloc( sizeof(struct arpaddr));
+			memcpy(pmw, &mw, sizeof(struct arpaddr));
+			addrhash[hashval] = pmw;
+			ips ++;
+		}
+		if ( bytes < 0 ) {
+			mesg(M_ERR, "macwatch: %s: read(): %s", DBFILENAME, strerror(errno));
+		}
+		/* Was the last record truncated? */
+		if ( (bytes > 0) && (bytes < (int) sizeof(struct arpaddr))) {
+			mesg(M_WARN, "macwatch: corrupted database %s", DBFILENAME);
+		}
+		mesg(M_INFO,"macwatch: read %i tuples from %s", ips, DBFILENAME);
+		close(fd);
+	}	
 	return err;
 }
 
@@ -209,5 +273,5 @@
 	.author_name 	= "John Leach",
 	.author_email 	= "john@johnleach.co.uk",
 	.ver_major 	= 0,
-	.ver_minor 	= 4,
+	.ver_minor 	= 5,
 };
