summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2014-05-18 11:16:55 -0700
committerGuy Harris <guy@alum.mit.edu>2014-05-18 11:16:55 -0700
commitda45f5a83f828aa5e8692834d580dc5e3eaacd1a (patch)
tree7870dd8d34508e8bba0fc5f0ccd1c5f953e4329e
parenteb87c17d99e2d4020f91a66e9433cc8eafb93ae1 (diff)
downloadlibpcap-da45f5a83f828aa5e8692834d580dc5e3eaacd1a.tar.gz
Support mod and XOR operators.
Same opcodes as on Linux. We support them in BPF filters, but warn, in the man page, that using them on anything other than Linux 3.7 or later will cause the filter to run in userland and thus require more resources and perhaps cause more packets to be dropped. (The filter will presumably be rejected by the kernel-mode code if it doesn't support BPF_MOD or BPF_XOR, and libpcap will fall back on running the filter in userland.)
-rw-r--r--bpf/net/bpf_filter.c23
-rw-r--r--bpf_image.c20
-rw-r--r--grammar.y2
-rw-r--r--optimize.c20
-rw-r--r--pcap-filter.manmisc.in17
-rw-r--r--pcap/bpf.h4
-rw-r--r--scanner.l2
7 files changed, 76 insertions, 12 deletions
diff --git a/bpf/net/bpf_filter.c b/bpf/net/bpf_filter.c
index 28c6df7c..ad689e16 100644
--- a/bpf/net/bpf_filter.c
+++ b/bpf/net/bpf_filter.c
@@ -464,6 +464,12 @@ bpf_filter(pc, p, wirelen, buflen)
A /= X;
continue;
+ case BPF_ALU|BPF_MOD|BPF_X:
+ if (X == 0)
+ return 0;
+ A %= X;
+ continue;
+
case BPF_ALU|BPF_AND|BPF_X:
A &= X;
continue;
@@ -472,6 +478,10 @@ bpf_filter(pc, p, wirelen, buflen)
A |= X;
continue;
+ case BPF_ALU|BPF_XOR|BPF_X:
+ A ^= X;
+ continue;
+
case BPF_ALU|BPF_LSH|BPF_X:
A <<= X;
continue;
@@ -496,6 +506,10 @@ bpf_filter(pc, p, wirelen, buflen)
A /= pc->k;
continue;
+ case BPF_ALU|BPF_MOD|BPF_K:
+ A %= pc->k;
+ continue;
+
case BPF_ALU|BPF_AND|BPF_K:
A &= pc->k;
continue;
@@ -504,6 +518,10 @@ bpf_filter(pc, p, wirelen, buflen)
A |= pc->k;
continue;
+ case BPF_ALU|BPF_XOR|BPF_K:
+ A ^= pc->k;
+ continue;
+
case BPF_ALU|BPF_LSH|BPF_K:
A <<= pc->k;
continue;
@@ -606,13 +624,16 @@ bpf_validate(f, len)
case BPF_MUL:
case BPF_OR:
case BPF_AND:
+ case BPF_XOR:
case BPF_LSH:
case BPF_RSH:
case BPF_NEG:
break;
case BPF_DIV:
+ case BPF_MOD:
/*
- * Check for constant division by 0.
+ * Check for constant division or modulus
+ * by 0.
*/
if (BPF_SRC(p->code) == BPF_K && p->k == 0)
return 0;
diff --git a/bpf_image.c b/bpf_image.c
index 2f16c453..3e9a23f5 100644
--- a/bpf_image.c
+++ b/bpf_image.c
@@ -211,6 +211,11 @@ bpf_image(p, n)
fmt = "x";
break;
+ case BPF_ALU|BPF_MOD|BPF_X:
+ op = "mod";
+ fmt = "x";
+ break;
+
case BPF_ALU|BPF_AND|BPF_X:
op = "and";
fmt = "x";
@@ -221,6 +226,11 @@ bpf_image(p, n)
fmt = "x";
break;
+ case BPF_ALU|BPF_XOR|BPF_X:
+ op = "xor";
+ fmt = "x";
+ break;
+
case BPF_ALU|BPF_LSH|BPF_X:
op = "lsh";
fmt = "x";
@@ -251,6 +261,11 @@ bpf_image(p, n)
fmt = "#%d";
break;
+ case BPF_ALU|BPF_MOD|BPF_K:
+ op = "mod";
+ fmt = "#%d";
+ break;
+
case BPF_ALU|BPF_AND|BPF_K:
op = "and";
fmt = "#0x%x";
@@ -261,6 +276,11 @@ bpf_image(p, n)
fmt = "#0x%x";
break;
+ case BPF_ALU|BPF_XOR|BPF_K:
+ op = "xor";
+ fmt = "#0x%x";
+ break;
+
case BPF_ALU|BPF_LSH|BPF_K:
op = "lsh";
fmt = "#%d";
diff --git a/grammar.y b/grammar.y
index 05785bbf..b7320153 100644
--- a/grammar.y
+++ b/grammar.y
@@ -614,8 +614,10 @@ narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); }
| arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); }
| arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); }
| arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); }
+ | arth '%' arth { $$ = gen_arth(BPF_MOD, $1, $3); }
| arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); }
| arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); }
+ | arth '^' arth { $$ = gen_arth(BPF_XOR, $1, $3); }
| arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); }
| arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); }
| '-' arth %prec UMINUS { $$ = gen_neg($2); }
diff --git a/optimize.c b/optimize.c
index d9bb4ee5..feaf2017 100644
--- a/optimize.c
+++ b/optimize.c
@@ -606,6 +606,12 @@ fold_op(struct stmt *s, int v0, int v1)
a /= b;
break;
+ case BPF_MOD:
+ if (b == 0)
+ bpf_error("modulus by zero");
+ a %= b;
+ break;
+
case BPF_AND:
a &= b;
break;
@@ -614,6 +620,10 @@ fold_op(struct stmt *s, int v0, int v1)
a |= b;
break;
+ case BPF_XOR:
+ a ^= b;
+ break;
+
case BPF_LSH:
a <<= b;
break;
@@ -974,8 +984,10 @@ opt_stmt(struct stmt *s, int val[], int alter)
case BPF_ALU|BPF_SUB|BPF_K:
case BPF_ALU|BPF_MUL|BPF_K:
case BPF_ALU|BPF_DIV|BPF_K:
+ case BPF_ALU|BPF_MOD|BPF_K:
case BPF_ALU|BPF_AND|BPF_K:
case BPF_ALU|BPF_OR|BPF_K:
+ case BPF_ALU|BPF_XOR|BPF_K:
case BPF_ALU|BPF_LSH|BPF_K:
case BPF_ALU|BPF_RSH|BPF_K:
op = BPF_OP(s->code);
@@ -986,7 +998,7 @@ opt_stmt(struct stmt *s, int val[], int alter)
* fixup the generated math code */
if (op == BPF_ADD ||
op == BPF_LSH || op == BPF_RSH ||
- op == BPF_OR) {
+ op == BPF_OR || op == BPF_XOR) {
s->code = NOP;
break;
}
@@ -1009,8 +1021,10 @@ opt_stmt(struct stmt *s, int val[], int alter)
case BPF_ALU|BPF_SUB|BPF_X:
case BPF_ALU|BPF_MUL|BPF_X:
case BPF_ALU|BPF_DIV|BPF_X:
+ case BPF_ALU|BPF_MOD|BPF_X:
case BPF_ALU|BPF_AND|BPF_X:
case BPF_ALU|BPF_OR|BPF_X:
+ case BPF_ALU|BPF_XOR|BPF_X:
case BPF_ALU|BPF_LSH|BPF_X:
case BPF_ALU|BPF_RSH|BPF_X:
op = BPF_OP(s->code);
@@ -1037,12 +1051,12 @@ opt_stmt(struct stmt *s, int val[], int alter)
*/
if (alter && vmap[val[A_ATOM]].is_const
&& vmap[val[A_ATOM]].const_val == 0) {
- if (op == BPF_ADD || op == BPF_OR) {
+ if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) {
s->code = BPF_MISC|BPF_TXA;
vstore(s, &val[A_ATOM], val[X_ATOM], alter);
break;
}
- else if (op == BPF_MUL || op == BPF_DIV ||
+ else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD ||
op == BPF_AND || op == BPF_LSH || op == BPF_RSH) {
s->code = BPF_LD|BPF_IMM;
s->k = 0;
diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in
index 6847b25a..a71e5dc2 100644
--- a/pcap-filter.manmisc.in
+++ b/pcap-filter.manmisc.in
@@ -330,8 +330,9 @@ The packet may contain, for example,
authentication header, routing header, or hop-by-hop option header,
between IPv6 header and TCP header.
The BPF code emitted by this primitive is complex and
-cannot be optimized by the BPF optimizer code, so this can be somewhat
-slow.
+cannot be optimized by the BPF optimizer code, and is not supported by
+filter engines in the kernel, so this can be somewhat slow, and may
+cause more packets to be dropped.
.IP "\fBip protochain \fIprotocol\fR"
Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4.
.IP "\fBprotochain \fIprotocol\fR"
@@ -741,11 +742,17 @@ Release, or Release Done message.
True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =,
!=, and \fIexpr\fR is an arithmetic expression composed of integer
constants (expressed in standard C syntax), the normal binary operators
-[+, -, *, /, &, |, <<, >>], a length operator, and special packet data
+[+, -, *, /, %, &, |, ^, <<, >>], a length operator, and special packet data
accessors. Note that all comparisons are unsigned, so that, for example,
0x80000000 and 0xffffffff are > 0.
-To access
-data inside the packet, use the following syntax:
+.IP
+The % and ^ operators are currently only supported for filtering in the
+kernel on Linux with 3.7 and later kernels; on all other systems, if
+those operators are used, filtering will be done in user mode, which
+will increase the overhead of capturing packets and may cause more
+packets to be dropped.
+.IP
+To access data inside the packet, use the following syntax:
.in +.5i
.nf
\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR
diff --git a/pcap/bpf.h b/pcap/bpf.h
index e8ef2099..a7e187b0 100644
--- a/pcap/bpf.h
+++ b/pcap/bpf.h
@@ -1368,8 +1368,8 @@ struct bpf_program {
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
-/* BPF_MOD 0x90 Linux modulo (%) operator */
-/* BPF_XOR 0xa0 Linux XOR (^) operator */
+#define BPF_MOD 0x90 /* from Linux */
+#define BPF_XOR 0xa0 /* from Linux */
/* 0xb0 reserved */
/* 0xc0 reserved */
/* 0xd0 reserved */
diff --git a/scanner.l b/scanner.l
index 73f426bd..a247c993 100644
--- a/scanner.l
+++ b/scanner.l
@@ -319,7 +319,7 @@ hdpc return HDPC;
hsls return HSLS;
[ \r\n\t] ;
-[+\-*/:\[\]!<>()&|=] return yytext[0];
+[+\-*/%:\[\]!<>()&|\^=] return yytext[0];
">=" return GEQ;
"<=" return LEQ;
"!=" return NEQ;