| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 
 | Author: Stefan Voelkel <bd@bc-bd.org>
Description: allow specifying a custom pcap filter
Bug-Debian: https://bugs.debian.org/600886
Giving the user an option to specify a custom pcap filter is both very
versatile (can be used to satisfy the request from multiple wishlist bugs) and
little intrusive (the code is only run during startup) addition.
Slightly adjusted by Lukas Schwaighofer <lukas@schwaighofer.name> from the
patch submitted by Stefan Voelkel <bd@bc-bd.org> to the Debian BTS.
---
 arpwatch.8 | 15 +++++++++++++++
 arpwatch.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 62 insertions(+), 1 deletion(-)
--- a/arpwatch.8
+++ b/arpwatch.8
@@ -68,6 +68,14 @@
 .br
 .ti +8
 [
+.B -F
+.I filter
+]
+.\" **
+.\" **
+.br
+.ti +8
+[
 .B -s
 .I sendmail_path
 ]
@@ -182,6 +190,16 @@
 .\" **
 .\" **
 .LP
+(Debian) The
+.B -F
+option is used to specify a pcap filter, which provides a generic way of
+ignoring specific packets.  The applied pcap filter will be "(arp or rarp) and
+not vlan and (filter)".  See
+.BR pcap-filter (7)
+for the syntax of that string.
+.\" **
+.\" **
+.LP
 (Debian) The
 .B -s
 flag is used to specify the path to the sendmail program.
--- a/arpwatch.c
+++ b/arpwatch.c
@@ -166,6 +166,40 @@
       syslog(LOG_INFO, "Running as uid=%d gid=%d", getuid(), getgid());
 }
 
+int compile_filter(pcap_t *p, struct bpf_program *fp, const char *filter_user,
+	bpf_u_int32 netmask)
+{
+	int len, result;
+
+	char *filter = NULL;
+	static const char filter_default[] = "(arp or rarp) and not vlan";
+	// will get appended with " and ()" (7 characters), where the filter
+	// specified by the user will be added between the brackets
+
+	if (filter_user && strlen(filter_user)) {
+		/* calculate needed space for filter string. */
+		len = strlen(filter_user) + strlen(filter_default) + 7 + 1;
+		filter = malloc(len);
+		if (!filter) {
+			syslog(LOG_ERR, "compile_filter: out of memory");
+			return -1;
+		}
+		result = snprintf(filter, len, "%s and (%s)", filter_default, filter_user);
+		if (result != len - 1) {
+			syslog(LOG_ERR, "compile_filter: snprintf() error");
+			free(filter);
+			return -1;
+		}
+		syslog(LOG_INFO, "using pcap filter '%s'", filter);
+		result = pcap_compile(p, fp, filter, 1, netmask);
+		free(filter);
+	} else {
+		result = pcap_compile(p, fp, filter_default, 1, netmask);
+	}
+
+	return result;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -179,6 +213,7 @@
 	struct bpf_program code;
 	char errbuf[PCAP_ERRBUF_SIZE];
 	char* username = NULL;
+	char *filter_user = NULL;
 	char options[] =
 		"d"
 		/**/
@@ -186,6 +221,9 @@
 		"f:"
 		/**/
 		/**/
+		"F:"
+		/**/
+		/**/
 		"i:"
 		/**/
 		/**/
@@ -260,6 +298,10 @@
 			arpfile = optarg;
 			break;
 
+		case 'F':
+			filter_user = strdup(optarg);
+			break;
+
 		case 'i':
 			interface = optarg;
 			break;
@@ -443,10 +485,11 @@
 	}
 
 	/* Compile and install filter */
-	if (pcap_compile(pd, &code, "(arp or rarp) and not vlan", 1, netmask) < 0) {
+	if (compile_filter(pd, &code, filter_user, netmask) < 0) {
 		syslog(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd));
 		exit(1);
 	}
+	free(filter_user);
 	if (pcap_setfilter(pd, &code) < 0) {
 		syslog(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd));
 		exit(1);
@@ -915,6 +958,9 @@
 		"[-f datafile] "
 		/**/
 		/**/
+		"[-F \"filter\" ]"
+		/**/
+		/**/
 		"[-i interface] "
 		/**/
 		/**/
 |