/* * Xtables BPF extension * * Written by Willem de Bruijn (willemb@google.com) * Copyright Google, Inc. 2013 * Licensed under the GNU General Public License version 2 (GPLv2) */ #include <linux/netfilter/xt_bpf.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <xtables.h> #define BCODE_FILE_MAX_LEN_B 1024 enum { O_BCODE_STDIN = 0, }; static void bpf_help(void) { printf( "bpf match options:\n" "--bytecode <program> : a bpf program as generated by\n" " `nfbpf_compiler RAW <filter>`\n"); } static const struct xt_option_entry bpf_opts[] = { {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING}, XTOPT_TABLEEND, }; static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program, const char separator) { struct xt_bpf_info *bi = (void *) cb->data; const char *token; char sp; int i; /* parse head: length. */ if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 || sp != separator) xtables_error(PARAMETER_PROBLEM, "bpf: error parsing program length"); if (!bi->bpf_program_num_elem) xtables_error(PARAMETER_PROBLEM, "bpf: illegal zero length program"); if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR) xtables_error(PARAMETER_PROBLEM, "bpf: number of instructions exceeds maximum"); /* parse instructions. */ i = 0; token = bpf_program; while ((token = strchr(token, separator)) && (++token)[0]) { if (i >= bi->bpf_program_num_elem) xtables_error(PARAMETER_PROBLEM, "bpf: real program length exceeds" " the encoded length parameter"); if (sscanf(token, "%hu %hhu %hhu %u,", &bi->bpf_program[i].code, &bi->bpf_program[i].jt, &bi->bpf_program[i].jf, &bi->bpf_program[i].k) != 4) xtables_error(PARAMETER_PROBLEM, "bpf: error at instr %d", i); i++; } if (i != bi->bpf_program_num_elem) xtables_error(PARAMETER_PROBLEM, "bpf: parsed program length is less than the" " encoded length parameter"); } static void bpf_parse(struct xt_option_call *cb) { xtables_option_parse(cb); switch (cb->entry->id) { case O_BCODE_STDIN: bpf_parse_string(cb, cb->arg, ','); break; default: xtables_error(PARAMETER_PROBLEM, "bpf: unknown option"); } } static void bpf_print_code(const void *ip, const struct xt_entry_match *match) { const struct xt_bpf_info *info = (void *) match->data; int i; for (i = 0; i < info->bpf_program_num_elem-1; i++) printf("%hu %hhu %hhu %u,", info->bpf_program[i].code, info->bpf_program[i].jt, info->bpf_program[i].jf, info->bpf_program[i].k); printf("%hu %hhu %hhu %u", info->bpf_program[i].code, info->bpf_program[i].jt, info->bpf_program[i].jf, info->bpf_program[i].k); } static void bpf_save(const void *ip, const struct xt_entry_match *match) { const struct xt_bpf_info *info = (void *) match->data; printf(" --bytecode \"%hu,", info->bpf_program_num_elem); bpf_print_code(ip, match); printf("\""); } static void bpf_fcheck(struct xt_fcheck_call *cb) { if (!(cb->xflags & (1 << O_BCODE_STDIN))) xtables_error(PARAMETER_PROBLEM, "bpf: missing --bytecode parameter"); } static void bpf_print(const void *ip, const struct xt_entry_match *match, int numeric) { printf("match bpf "); return bpf_print_code(ip, match); } static struct xtables_match bpf_match = { .family = NFPROTO_UNSPEC, .name = "bpf", .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_bpf_info)), .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)), .help = bpf_help, .print = bpf_print, .save = bpf_save, .x6_parse = bpf_parse, .x6_fcheck = bpf_fcheck, .x6_options = bpf_opts, }; void _init(void) { xtables_register_match(&bpf_match); }