summaryrefslogtreecommitdiff
path: root/bpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'bpf.c')
-rw-r--r--bpf.c765
1 files changed, 765 insertions, 0 deletions
diff --git a/bpf.c b/bpf.c
new file mode 100644
index 0000000..dc7e3cb
--- /dev/null
+++ b/bpf.c
@@ -0,0 +1,765 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Copyright 2009 - 2012 Daniel Borkmann.
+ * Copyright 2009, 2010 Emmanuel Roullit.
+ * Copyright 1990-1996 The Regents of the University of
+ * California. All rights reserved. (3-clause BSD license)
+ * Subject to the GPL, version 2.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "bpf.h"
+#include "xmalloc.h"
+#include "xutils.h"
+#include "die.h"
+
+#define EXTRACT_SHORT(packet) \
+ ((unsigned short) ntohs(*(unsigned short *) packet))
+#define EXTRACT_LONG(packet) \
+ (ntohl(*(unsigned long *) packet))
+
+#ifndef BPF_MEMWORDS
+# define BPF_MEMWORDS 16
+#endif
+
+#define BPF_LD_B (BPF_LD | BPF_B)
+#define BPF_LD_H (BPF_LD | BPF_H)
+#define BPF_LD_W (BPF_LD | BPF_W)
+#define BPF_LDX_B (BPF_LDX | BPF_B)
+#define BPF_LDX_W (BPF_LDX | BPF_W)
+#define BPF_JMP_JA (BPF_JMP | BPF_JA)
+#define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ)
+#define BPF_JMP_JGT (BPF_JMP | BPF_JGT)
+#define BPF_JMP_JGE (BPF_JMP | BPF_JGE)
+#define BPF_JMP_JSET (BPF_JMP | BPF_JSET)
+#define BPF_ALU_ADD (BPF_ALU | BPF_ADD)
+#define BPF_ALU_SUB (BPF_ALU | BPF_SUB)
+#define BPF_ALU_MUL (BPF_ALU | BPF_MUL)
+#define BPF_ALU_DIV (BPF_ALU | BPF_DIV)
+#define BPF_ALU_MOD (BPF_ALU | BPF_MOD)
+#define BPF_ALU_NEG (BPF_ALU | BPF_NEG)
+#define BPF_ALU_AND (BPF_ALU | BPF_AND)
+#define BPF_ALU_OR (BPF_ALU | BPF_OR)
+#define BPF_ALU_XOR (BPF_ALU | BPF_XOR)
+#define BPF_ALU_LSH (BPF_ALU | BPF_LSH)
+#define BPF_ALU_RSH (BPF_ALU | BPF_RSH)
+#define BPF_MISC_TAX (BPF_MISC | BPF_TAX)
+#define BPF_MISC_TXA (BPF_MISC | BPF_TXA)
+
+static const char *op_table[] = {
+ [BPF_LD_B] = "ldb",
+ [BPF_LD_H] = "ldh",
+ [BPF_LD_W] = "ld",
+ [BPF_LDX] = "ldx",
+ [BPF_LDX_B] = "ldxb",
+ [BPF_ST] = "st",
+ [BPF_STX] = "stx",
+ [BPF_JMP_JA] = "ja",
+ [BPF_JMP_JEQ] = "jeq",
+ [BPF_JMP_JGT] = "jgt",
+ [BPF_JMP_JGE] = "jge",
+ [BPF_JMP_JSET] = "jset",
+ [BPF_ALU_ADD] = "add",
+ [BPF_ALU_SUB] = "sub",
+ [BPF_ALU_MUL] = "mul",
+ [BPF_ALU_DIV] = "div",
+ [BPF_ALU_MOD] = "mod",
+ [BPF_ALU_NEG] = "neg",
+ [BPF_ALU_AND] = "and",
+ [BPF_ALU_OR] = "or",
+ [BPF_ALU_XOR] = "xor",
+ [BPF_ALU_LSH] = "lsh",
+ [BPF_ALU_RSH] = "rsh",
+ [BPF_RET] = "ret",
+ [BPF_MISC_TAX] = "tax",
+ [BPF_MISC_TXA] = "txa",
+};
+
+void bpf_dump_op_table(void)
+{
+ int i;
+ for (i = 0; i < array_size(op_table); ++i) {
+ if (op_table[i])
+ printf("%s\n", op_table[i]);
+ }
+}
+
+static const char *bpf_dump_linux_k(uint32_t k)
+{
+ switch (k) {
+ default:
+ return "[%d]";
+ case SKF_AD_OFF + SKF_AD_PROTOCOL:
+ return "#proto";
+ case SKF_AD_OFF + SKF_AD_PKTTYPE:
+ return "#type";
+ case SKF_AD_OFF + SKF_AD_IFINDEX:
+ return "#ifidx";
+ case SKF_AD_OFF + SKF_AD_NLATTR:
+ return "#nla";
+ case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
+ return "#nlan";
+ case SKF_AD_OFF + SKF_AD_MARK:
+ return "#mark";
+ case SKF_AD_OFF + SKF_AD_QUEUE:
+ return "#queue";
+ case SKF_AD_OFF + SKF_AD_HATYPE:
+ return "#hatype";
+ case SKF_AD_OFF + SKF_AD_RXHASH:
+ return "#rxhash";
+ case SKF_AD_OFF + SKF_AD_CPU:
+ return "#cpu";
+ case SKF_AD_OFF + SKF_AD_VLAN_TAG:
+ return "#vlant";
+ case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
+ return "#vlanp";
+ }
+}
+
+static char *__bpf_dump(const struct sock_filter bpf, int n)
+{
+ int v;
+ const char *fmt, *op;
+ static char image[256];
+ char operand[64];
+
+ v = bpf.k;
+ switch (bpf.code) {
+ default:
+ op = "unimp";
+ fmt = "0x%x";
+ v = bpf.code;
+ break;
+ case BPF_RET | BPF_K:
+ op = op_table[BPF_RET];
+ fmt = "#0x%x";
+ break;
+ case BPF_RET | BPF_A:
+ op = op_table[BPF_RET];
+ fmt = "a";
+ break;
+ case BPF_RET | BPF_X:
+ op = op_table[BPF_RET];
+ fmt = "x";
+ break;
+ case BPF_LD_W | BPF_ABS:
+ op = op_table[BPF_LD_W];
+ fmt = bpf_dump_linux_k(bpf.k);
+ break;
+ case BPF_LD_H | BPF_ABS:
+ op = op_table[BPF_LD_H];
+ fmt = bpf_dump_linux_k(bpf.k);
+ break;
+ case BPF_LD_B | BPF_ABS:
+ op = op_table[BPF_LD_B];
+ fmt = bpf_dump_linux_k(bpf.k);
+ break;
+ case BPF_LD_W | BPF_LEN:
+ op = op_table[BPF_LD_W];
+ fmt = "#len";
+ break;
+ case BPF_LD_W | BPF_IND:
+ op = op_table[BPF_LD_W];
+ fmt = "[x + %d]";
+ break;
+ case BPF_LD_H | BPF_IND:
+ op = op_table[BPF_LD_H];
+ fmt = "[x + %d]";
+ break;
+ case BPF_LD_B | BPF_IND:
+ op = op_table[BPF_LD_B];
+ fmt = "[x + %d]";
+ break;
+ case BPF_LD | BPF_IMM:
+ op = op_table[BPF_LD_W];
+ fmt = "#0x%x";
+ break;
+ case BPF_LDX | BPF_IMM:
+ op = op_table[BPF_LDX];
+ fmt = "#0x%x";
+ break;
+ case BPF_LDX_B | BPF_MSH:
+ op = op_table[BPF_LDX_B];
+ fmt = "4*([%d]&0xf)";
+ break;
+ case BPF_LD | BPF_MEM:
+ op = op_table[BPF_LD_W];
+ fmt = "M[%d]";
+ break;
+ case BPF_LDX | BPF_MEM:
+ op = op_table[BPF_LDX];
+ fmt = "M[%d]";
+ break;
+ case BPF_ST:
+ op = op_table[BPF_ST];
+ fmt = "M[%d]";
+ break;
+ case BPF_STX:
+ op = op_table[BPF_STX];
+ fmt = "M[%d]";
+ break;
+ case BPF_JMP_JA:
+ op = op_table[BPF_JMP_JA];
+ fmt = "%d";
+ v = n + 1 + bpf.k;
+ break;
+ case BPF_JMP_JGT | BPF_K:
+ op = op_table[BPF_JMP_JGT];
+ fmt = "#0x%x";
+ break;
+ case BPF_JMP_JGE | BPF_K:
+ op = op_table[BPF_JMP_JGE];
+ fmt = "#0x%x";
+ break;
+ case BPF_JMP_JEQ | BPF_K:
+ op = op_table[BPF_JMP_JEQ];
+ fmt = "#0x%x";
+ break;
+ case BPF_JMP_JSET | BPF_K:
+ op = op_table[BPF_JMP_JSET];
+ fmt = "#0x%x";
+ break;
+ case BPF_JMP_JGT | BPF_X:
+ op = op_table[BPF_JMP_JGT];
+ fmt = "x";
+ break;
+ case BPF_JMP_JGE | BPF_X:
+ op = op_table[BPF_JMP_JGE];
+ fmt = "x";
+ break;
+ case BPF_JMP_JEQ | BPF_X:
+ op = op_table[BPF_JMP_JEQ];
+ fmt = "x";
+ break;
+ case BPF_JMP_JSET | BPF_X:
+ op = op_table[BPF_JMP_JSET];
+ fmt = "x";
+ break;
+ case BPF_ALU_ADD | BPF_X:
+ op = op_table[BPF_ALU_ADD];
+ fmt = "x";
+ break;
+ case BPF_ALU_SUB | BPF_X:
+ op = op_table[BPF_ALU_SUB];
+ fmt = "x";
+ break;
+ case BPF_ALU_MUL | BPF_X:
+ op = op_table[BPF_ALU_MUL];
+ fmt = "x";
+ break;
+ case BPF_ALU_DIV | BPF_X:
+ op = op_table[BPF_ALU_DIV];
+ fmt = "x";
+ break;
+ case BPF_ALU_MOD | BPF_X:
+ op = op_table[BPF_ALU_MOD];
+ fmt = "x";
+ break;
+ case BPF_ALU_AND | BPF_X:
+ op = op_table[BPF_ALU_AND];
+ fmt = "x";
+ break;
+ case BPF_ALU_OR | BPF_X:
+ op = op_table[BPF_ALU_OR];
+ fmt = "x";
+ break;
+ case BPF_ALU_XOR | BPF_X:
+ op = op_table[BPF_ALU_XOR];
+ fmt = "x";
+ break;
+ case BPF_ALU_LSH | BPF_X:
+ op = op_table[BPF_ALU_LSH];
+ fmt = "x";
+ break;
+ case BPF_ALU_RSH | BPF_X:
+ op = op_table[BPF_ALU_RSH];
+ fmt = "x";
+ break;
+ case BPF_ALU_ADD | BPF_K:
+ op = op_table[BPF_ALU_ADD];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_SUB | BPF_K:
+ op = op_table[BPF_ALU_SUB];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_MUL | BPF_K:
+ op = op_table[BPF_ALU_MUL];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_DIV | BPF_K:
+ op = op_table[BPF_ALU_DIV];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_MOD | BPF_K:
+ op = op_table[BPF_ALU_MOD];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_AND | BPF_K:
+ op = op_table[BPF_ALU_AND];
+ fmt = "#0x%x";
+ break;
+ case BPF_ALU_OR | BPF_K:
+ op = op_table[BPF_ALU_OR];
+ fmt = "#0x%x";
+ break;
+ case BPF_ALU_XOR | BPF_K:
+ op = op_table[BPF_ALU_XOR];
+ fmt = "#0x%x";
+ break;
+ case BPF_ALU_LSH | BPF_K:
+ op = op_table[BPF_ALU_LSH];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_RSH | BPF_K:
+ op = op_table[BPF_ALU_RSH];
+ fmt = "#%d";
+ break;
+ case BPF_ALU_NEG:
+ op = op_table[BPF_ALU_NEG];
+ fmt = "";
+ break;
+ case BPF_MISC_TAX:
+ op = op_table[BPF_MISC_TAX];
+ fmt = "";
+ break;
+ case BPF_MISC_TXA:
+ op = op_table[BPF_MISC_TXA];
+ fmt = "";
+ break;
+ }
+
+ slprintf_nocheck(operand, sizeof(operand), fmt, v);
+ slprintf_nocheck(image, sizeof(image),
+ (BPF_CLASS(bpf.code) == BPF_JMP &&
+ BPF_OP(bpf.code) != BPF_JA) ?
+ " L%d: %s %s, L%d, L%d" : " L%d: %s %s",
+ n, op, operand, n + 1 + bpf.jt, n + 1 + bpf.jf);
+ return image;
+}
+
+void bpf_dump_all(struct sock_fprog *bpf)
+{
+ int i;
+ for (i = 0; i < bpf->len; ++i)
+ printf("%s\n", __bpf_dump(bpf->filter[i], i));
+}
+
+void bpf_attach_to_sock(int sock, struct sock_fprog *bpf)
+{
+ int ret;
+
+ if (bpf->filter[0].code == BPF_RET &&
+ bpf->filter[0].k == 0xFFFFFFFF)
+ return;
+
+ ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
+ bpf, sizeof(*bpf));
+ if (ret < 0)
+ panic("Cannot attach filter to socket!\n");
+}
+
+void bpf_detach_from_sock(int sock)
+{
+ int ret, empty = 0;
+
+ ret = setsockopt(sock, SOL_SOCKET, SO_DETACH_FILTER,
+ &empty, sizeof(empty));
+ if (ret < 0)
+ panic("Cannot detach filter from socket!\n");
+}
+
+int enable_kernel_bpf_jit_compiler(void)
+{
+ int fd;
+ ssize_t ret;
+ char *file = "/proc/sys/net/core/bpf_jit_enable";
+
+ fd = open(file, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ ret = write(fd, "1", strlen("1"));
+
+ close(fd);
+ return ret;
+}
+
+int __bpf_validate(const struct sock_fprog *bpf)
+{
+ uint32_t i, from;
+ const struct sock_filter *p;
+
+ if (!bpf)
+ return 0;
+ if (bpf->len < 1)
+ return 0;
+
+ for (i = 0; i < bpf->len; ++i) {
+ p = &bpf->filter[i];
+ switch (BPF_CLASS(p->code)) {
+ /* Check that memory operations use valid addresses. */
+ case BPF_LD:
+ case BPF_LDX:
+ switch (BPF_MODE(p->code)) {
+ case BPF_IMM:
+ break;
+ case BPF_ABS:
+ case BPF_IND:
+ case BPF_MSH:
+ /* There's no maximum packet data size
+ * in userland. The runtime packet length
+ * check suffices.
+ */
+ break;
+ case BPF_MEM:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_LEN:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_ST:
+ case BPF_STX:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_ALU:
+ switch (BPF_OP(p->code)) {
+ case BPF_ADD:
+ case BPF_SUB:
+ case BPF_MUL:
+ case BPF_OR:
+ case BPF_XOR:
+ case BPF_AND:
+ case BPF_LSH:
+ case BPF_RSH:
+ case BPF_NEG:
+ break;
+ case BPF_DIV:
+ case BPF_MOD:
+ /* Check for constant division by 0 (undefined
+ * for div and mod).
+ */
+ if (BPF_RVAL(p->code) == BPF_K && p->k == 0)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_JMP:
+ /* Check that jumps are within the code block,
+ * and that unconditional branches don't go
+ * backwards as a result of an overflow.
+ * Unconditional branches have a 32-bit offset,
+ * so they could overflow; we check to make
+ * sure they don't. Conditional branches have
+ * an 8-bit offset, and the from address is <=
+ * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
+ * is sufficiently small that adding 255 to it
+ * won't overflow.
+ *
+ * We know that len is <= BPF_MAXINSNS, and we
+ * assume that BPF_MAXINSNS is < the maximum size
+ * of a u_int, so that i + 1 doesn't overflow.
+ *
+ * For userland, we don't know that the from
+ * or len are <= BPF_MAXINSNS, but we know that
+ * from <= len, and, except on a 64-bit system,
+ * it's unlikely that len, if it truly reflects
+ * the size of the program we've been handed,
+ * will be anywhere near the maximum size of
+ * a u_int. We also don't check for backward
+ * branches, as we currently support them in
+ * userland for the protochain operation.
+ */
+ from = i + 1;
+ switch (BPF_OP(p->code)) {
+ case BPF_JA:
+ if (from + p->k >= bpf->len)
+ return 0;
+ break;
+ case BPF_JEQ:
+ case BPF_JGT:
+ case BPF_JGE:
+ case BPF_JSET:
+ if (from + p->jt >= bpf->len ||
+ from + p->jf >= bpf->len)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_RET:
+ break;
+ case BPF_MISC:
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ return BPF_CLASS(bpf->filter[bpf->len - 1].code) == BPF_RET;
+}
+
+uint32_t bpf_run_filter(const struct sock_fprog * fcode, uint8_t * packet,
+ size_t plen)
+{
+ /* XXX: caplen == len */
+ uint32_t A, X;
+ uint32_t k;
+ struct sock_filter *bpf;
+ int32_t mem[BPF_MEMWORDS] = { 0, };
+
+ if (fcode == NULL || fcode->filter == NULL || fcode->len == 0)
+ return 0xFFFFFFFF;
+
+ A = 0;
+ X = 0;
+
+ bpf = fcode->filter;
+ --bpf;
+ while (1) {
+ ++bpf;
+ switch (bpf->code) {
+ default:
+ return 0;
+ case BPF_RET | BPF_K:
+ return (uint32_t) bpf->k;
+ case BPF_RET | BPF_A:
+ return (uint32_t) A;
+ case BPF_LD_W | BPF_ABS:
+ /* No Linux extensions supported here! */
+ k = bpf->k;
+ if (k + sizeof(int32_t) > plen)
+ return 0;
+ A = EXTRACT_LONG(&packet[k]);
+ continue;
+ case BPF_LD_H | BPF_ABS:
+ /* No Linux extensions supported here! */
+ k = bpf->k;
+ if (k + sizeof(short) > plen)
+ return 0;
+ A = EXTRACT_SHORT(&packet[k]);
+ continue;
+ case BPF_LD_B | BPF_ABS:
+ /* No Linux extensions supported here! */
+ k = bpf->k;
+ if (k >= plen)
+ return 0;
+ A = packet[k];
+ continue;
+ case BPF_LD_W | BPF_LEN:
+ A = plen;
+ continue;
+ case BPF_LDX_W | BPF_LEN:
+ X = plen;
+ continue;
+ case BPF_LD_W | BPF_IND:
+ k = X + bpf->k;
+ if (k + sizeof(int32_t) > plen)
+ return 0;
+ A = EXTRACT_LONG(&packet[k]);
+ continue;
+ case BPF_LD_H | BPF_IND:
+ k = X + bpf->k;
+ if (k + sizeof(short) > plen)
+ return 0;
+ A = EXTRACT_SHORT(&packet[k]);
+ continue;
+ case BPF_LD_B | BPF_IND:
+ k = X + bpf->k;
+ if (k >= plen)
+ return 0;
+ A = packet[k];
+ continue;
+ case BPF_LDX_B | BPF_MSH:
+ k = bpf->k;
+ if (k >= plen)
+ return 0;
+ X = (packet[bpf->k] & 0xf) << 2;
+ continue;
+ case BPF_LD | BPF_IMM:
+ A = bpf->k;
+ continue;
+ case BPF_LDX | BPF_IMM:
+ X = bpf->k;
+ continue;
+ case BPF_LD | BPF_MEM:
+ A = mem[bpf->k];
+ continue;
+ case BPF_LDX | BPF_MEM:
+ X = mem[bpf->k];
+ continue;
+ case BPF_ST:
+ mem[bpf->k] = A;
+ continue;
+ case BPF_STX:
+ mem[bpf->k] = X;
+ continue;
+ case BPF_JMP_JA:
+ bpf += bpf->k;
+ continue;
+ case BPF_JMP_JGT | BPF_K:
+ bpf += (A > bpf->k) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JGE | BPF_K:
+ bpf += (A >= bpf->k) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JEQ | BPF_K:
+ bpf += (A == bpf->k) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JSET | BPF_K:
+ bpf += (A & bpf->k) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JGT | BPF_X:
+ bpf += (A > X) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JGE | BPF_X:
+ bpf += (A >= X) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JEQ | BPF_X:
+ bpf += (A == X) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_JMP_JSET | BPF_X:
+ bpf += (A & X) ? bpf->jt : bpf->jf;
+ continue;
+ case BPF_ALU_ADD | BPF_X:
+ A += X;
+ continue;
+ case BPF_ALU_SUB | BPF_X:
+ A -= X;
+ continue;
+ case BPF_ALU_MUL | BPF_X:
+ A *= X;
+ continue;
+ case BPF_ALU_DIV | BPF_X:
+ if (X == 0)
+ return 0;
+ A /= X;
+ continue;
+ case BPF_ALU_MOD | BPF_X:
+ if (X == 0)
+ return 0;
+ A %= X;
+ continue;
+ case BPF_ALU_AND | BPF_X:
+ A &= X;
+ continue;
+ case BPF_ALU_OR | BPF_X:
+ A |= X;
+ continue;
+ case BPF_ALU_XOR | BPF_X:
+ A ^= X;
+ continue;
+ case BPF_ALU_LSH | BPF_X:
+ A <<= X;
+ continue;
+ case BPF_ALU_RSH | BPF_X:
+ A >>= X;
+ continue;
+ case BPF_ALU_ADD | BPF_K:
+ A += bpf->k;
+ continue;
+ case BPF_ALU_SUB | BPF_K:
+ A -= bpf->k;
+ continue;
+ case BPF_ALU_MUL | BPF_K:
+ A *= bpf->k;
+ continue;
+ case BPF_ALU_DIV | BPF_K:
+ A /= bpf->k;
+ continue;
+ case BPF_ALU_MOD | BPF_K:
+ A %= bpf->k;
+ continue;
+ case BPF_ALU_AND | BPF_K:
+ A &= bpf->k;
+ continue;
+ case BPF_ALU_OR | BPF_K:
+ A |= bpf->k;
+ continue;
+ case BPF_ALU_XOR | BPF_K:
+ A ^= bpf->k;
+ continue;
+ case BPF_ALU_LSH | BPF_K:
+ A <<= bpf->k;
+ continue;
+ case BPF_ALU_RSH | BPF_K:
+ A >>= bpf->k;
+ continue;
+ case BPF_ALU_NEG:
+ A = -A;
+ continue;
+ case BPF_MISC_TAX:
+ X = A;
+ continue;
+ case BPF_MISC_TXA:
+ A = X;
+ continue;
+ }
+ }
+}
+
+void bpf_parse_rules(char *rulefile, struct sock_fprog *bpf, uint32_t link_type)
+{
+ int ret;
+ char buff[256];
+ struct sock_filter sf_single = { 0x06, 0, 0, 0xFFFFFFFF };
+ FILE *fp;
+
+ if (rulefile == NULL) {
+ bpf->len = 1;
+ bpf->filter = xmalloc(sizeof(sf_single));
+ fmemcpy(&bpf->filter[0], &sf_single, sizeof(sf_single));
+ return;
+ }
+
+ fp = fopen(rulefile, "r");
+ if (!fp) {
+ bpf_try_compile(rulefile, bpf, link_type);
+ return;
+ }
+
+ fmemset(buff, 0, sizeof(buff));
+ while (fgets(buff, sizeof(buff), fp) != NULL) {
+ buff[sizeof(buff) - 1] = 0;
+ if (buff[0] != '{') {
+ fmemset(buff, 0, sizeof(buff));
+ continue;
+ }
+
+ fmemset(&sf_single, 0, sizeof(sf_single));
+ ret = sscanf(buff, "{ 0x%x, %u, %u, 0x%08x },",
+ (unsigned int *) &sf_single.code,
+ (unsigned int *) &sf_single.jt,
+ (unsigned int *) &sf_single.jf,
+ (unsigned int *) &sf_single.k);
+ if (ret != 4)
+ panic("BPF syntax error!\n");
+
+ bpf->len++;
+ bpf->filter = xrealloc(bpf->filter, 1,
+ bpf->len * sizeof(sf_single));
+
+ fmemcpy(&bpf->filter[bpf->len - 1], &sf_single,
+ sizeof(sf_single));
+ fmemset(buff, 0, sizeof(buff));
+ }
+
+ fclose(fp);
+
+ if (__bpf_validate(bpf) == 0)
+ panic("This is not a valid BPF program!\n");
+}