| /* |
| * 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); |
| } |