From a7b0ee3852e05dc92bb98971c09e271d4d7f245e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 16 Mar 2013 19:04:39 +0100 Subject: bpfc: support different output formats Add different bpf opcode pretty printer to support a variety of output formats for netsniff-ng, xt_bpf, tcpdump, C-like and make future integration of formats easier. Signed-off-by: Daniel Borkmann --- bpf_parser.y | 70 +++++++++++++++++++++++++++++++++++++++++++++++++----------- bpfc.c | 32 ++++++++++++++++++--------- 2 files changed, 80 insertions(+), 22 deletions(-) diff --git a/bpf_parser.y b/bpf_parser.y index 4c35e07..7f6bcc8 100644 --- a/bpf_parser.y +++ b/bpf_parser.y @@ -25,7 +25,7 @@ #define MAX_INSTRUCTIONS 4096 -int compile_filter(char *file, int verbose, int bypass, int decimal); +int compile_filter(char *file, int verbose, int bypass, int format); static int curr_instr = 0; @@ -597,7 +597,60 @@ static void stage_2_label_reduce(void) } } -int compile_filter(char *file, int verbose, int bypass, int decimal) +static void pretty_printer_c(const struct sock_fprog *prog) +{ + int i; + + for (i = 0; i < prog->len; ++i) { + printf("{ 0x%x, %u, %u, 0x%08x },\n", + prog->filter[i].code, prog->filter[i].jt, + prog->filter[i].jf, prog->filter[i].k); + } +} + +static void pretty_printer_xt_bpf(const struct sock_fprog *prog) +{ + int i; + + printf("%d,", prog->len); + for (i = 0; i < prog->len; ++i) { + printf("%u %u %u %u,", + prog->filter[i].code, prog->filter[i].jt, + prog->filter[i].jf, prog->filter[i].k); + } + + fflush(stdout); +} + +static void pretty_printer_tcpdump(const struct sock_fprog *prog) +{ + int i; + + for (i = 0; i < prog->len; ++i) { + printf("%u %u %u %u\n", + prog->filter[i].code, prog->filter[i].jt, + prog->filter[i].jf, prog->filter[i].k); + } +} + +static void pretty_printer(const struct sock_fprog *prog, int format) +{ + switch (format) { + case 0: + pretty_printer_c(prog); + break; + case 1: + pretty_printer_xt_bpf(prog); + break; + case 2: + pretty_printer_tcpdump(prog); + break; + default: + bug(); + } +} + +int compile_filter(char *file, int verbose, int bypass, int format) { int i; struct sock_fprog res; @@ -645,17 +698,10 @@ int compile_filter(char *file, int verbose, int bypass, int decimal) if (verbose) printf("Result:\n"); - for (i = 0; i < res.len; ++i) { - if (decimal) { - printf("%u %u %u %u\n", - res.filter[i].code, res.filter[i].jt, - res.filter[i].jf, res.filter[i].k); - } else { - printf("{ 0x%x, %u, %u, 0x%08x },\n", - res.filter[i].code, res.filter[i].jt, - res.filter[i].jf, res.filter[i].k); - } + pretty_printer(&res, format); + + for (i = 0; i < res.len; ++i) { free(labels[i]); free(labels_jt[i]); free(labels_jf[i]); diff --git a/bpfc.c b/bpfc.c index 53ad5b3..2045512 100644 --- a/bpfc.c +++ b/bpfc.c @@ -17,11 +17,11 @@ #include "die.h" #include "bpf.h" -static const char *short_options = "vhi:VdbD"; +static const char *short_options = "vhi:Vdbf:"; static const struct option long_options[] = { {"input", required_argument, NULL, 'i'}, + {"format", required_argument, NULL, 'f'}, {"verbose", no_argument, NULL, 'V'}, - {"decimal", no_argument, NULL, 'D'}, {"bypass", no_argument, NULL, 'b'}, {"dump", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'v'}, @@ -29,7 +29,7 @@ static const struct option long_options[] = { {NULL, 0, NULL, 0} }; -extern int compile_filter(char *file, int verbose, int bypass, int decimal); +extern int compile_filter(char *file, int verbose, int bypass, int format); static void help(void) { @@ -38,15 +38,18 @@ static void help(void) "Usage: bpfc [options] || bpfc \n" "Options:\n" " -i|--input Berkeley Packet Filter file/stdin\n" - " -D|--decimal Decimal output, e.g. for xt_bpf\n" - " -V|--verbose Be more verbose\n" + " -f|--format Output format: C|netsniff-ng|xt_bpf|tcpdump\n" " -b|--bypass Bypass filter validation (e.g. for bug testing)\n" + " -V|--verbose Be more verbose\n" " -d|--dump Dump supported instruction table\n" " -v|--version Print version\n" " -h|--help Print this help\n\n" "Examples:\n" " bpfc fubar\n" - " bpfc -Dbi fubar\n" + " bpfc fubar > foo (bpfc -f C -i fubar > foo) --> netsniff-ng -f foo ...\n" + " bpfc -f tcpdump -i fubar > foo --> tcpdump -ddd like ...\n" + " bpfc -f xt_bpf -b -i fubar\n" + " iptables -A INPUT -m bpf --bytecode \"`./bpfc -f xt_bpf -i fubar`\" -j LOG\n" " bpfc - (read from stdin)\n\n" "Please report bugs to \n" "Copyright (C) 2011-2013 Daniel Borkmann ,\n" @@ -72,7 +75,7 @@ static void version(void) int main(int argc, char **argv) { - int ret, verbose = 0, c, opt_index, bypass = 0, decimal = 0; + int ret, verbose = 0, c, opt_index, bypass = 0, format = 0; char *file = NULL; setfsuid(getuid()); @@ -93,8 +96,16 @@ int main(int argc, char **argv) case 'V': verbose = 1; break; - case 'D': - decimal = 1; + case 'f': + if (!strncmp(optarg, "C", 1) || + !strncmp(optarg, "netsniff-ng", 11)) + format = 0; + else if (!strncmp(optarg, "xt_bpf", 6)) + format = 1; + else if (!strncmp(optarg, "tcpdump", 7)) + format = 2; + else + help(); break; case 'b': bypass = 1; @@ -108,6 +119,7 @@ int main(int argc, char **argv) case '?': switch (optopt) { case 'i': + case 'f': panic("Option -%c requires an argument!\n", optopt); default: @@ -125,7 +137,7 @@ int main(int argc, char **argv) if (!file) panic("No Berkeley Packet Filter program specified!\n"); - ret = compile_filter(file, verbose, bypass, decimal); + ret = compile_filter(file, verbose, bypass, format); xfree(file); return ret; -- cgit v1.2.3-54-g00ecf