1 /* 2 * Xtables BPF extension 3 * 4 * Written by Willem de Bruijn (willemb (at) google.com) 5 * Copyright Google, Inc. 2013 6 * Licensed under the GNU General Public License version 2 (GPLv2) 7 */ 8 9 #include <linux/netfilter/xt_bpf.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <sys/stat.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 #include <xtables.h> 19 20 #define BCODE_FILE_MAX_LEN_B 1024 21 22 enum { 23 O_BCODE_STDIN = 0, 24 }; 25 26 static void bpf_help(void) 27 { 28 printf( 29 "bpf match options:\n" 30 "--bytecode <program> : a bpf program as generated by\n" 31 " `nfbpf_compiler RAW <filter>`\n"); 32 } 33 34 static const struct xt_option_entry bpf_opts[] = { 35 {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING}, 36 XTOPT_TABLEEND, 37 }; 38 39 static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program, 40 const char separator) 41 { 42 struct xt_bpf_info *bi = (void *) cb->data; 43 const char *token; 44 char sp; 45 int i; 46 47 /* parse head: length. */ 48 if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 || 49 sp != separator) 50 xtables_error(PARAMETER_PROBLEM, 51 "bpf: error parsing program length"); 52 if (!bi->bpf_program_num_elem) 53 xtables_error(PARAMETER_PROBLEM, 54 "bpf: illegal zero length program"); 55 if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR) 56 xtables_error(PARAMETER_PROBLEM, 57 "bpf: number of instructions exceeds maximum"); 58 59 /* parse instructions. */ 60 i = 0; 61 token = bpf_program; 62 while ((token = strchr(token, separator)) && (++token)[0]) { 63 if (i >= bi->bpf_program_num_elem) 64 xtables_error(PARAMETER_PROBLEM, 65 "bpf: real program length exceeds" 66 " the encoded length parameter"); 67 if (sscanf(token, "%hu %hhu %hhu %u,", 68 &bi->bpf_program[i].code, 69 &bi->bpf_program[i].jt, 70 &bi->bpf_program[i].jf, 71 &bi->bpf_program[i].k) != 4) 72 xtables_error(PARAMETER_PROBLEM, 73 "bpf: error at instr %d", i); 74 i++; 75 } 76 77 if (i != bi->bpf_program_num_elem) 78 xtables_error(PARAMETER_PROBLEM, 79 "bpf: parsed program length is less than the" 80 " encoded length parameter"); 81 } 82 83 static void bpf_parse(struct xt_option_call *cb) 84 { 85 xtables_option_parse(cb); 86 switch (cb->entry->id) { 87 case O_BCODE_STDIN: 88 bpf_parse_string(cb, cb->arg, ','); 89 break; 90 default: 91 xtables_error(PARAMETER_PROBLEM, "bpf: unknown option"); 92 } 93 } 94 95 static void bpf_print_code(const void *ip, const struct xt_entry_match *match) 96 { 97 const struct xt_bpf_info *info = (void *) match->data; 98 int i; 99 100 for (i = 0; i < info->bpf_program_num_elem-1; i++) 101 printf("%hu %hhu %hhu %u,", info->bpf_program[i].code, 102 info->bpf_program[i].jt, 103 info->bpf_program[i].jf, 104 info->bpf_program[i].k); 105 106 printf("%hu %hhu %hhu %u", info->bpf_program[i].code, 107 info->bpf_program[i].jt, 108 info->bpf_program[i].jf, 109 info->bpf_program[i].k); 110 } 111 112 static void bpf_save(const void *ip, const struct xt_entry_match *match) 113 { 114 const struct xt_bpf_info *info = (void *) match->data; 115 116 printf(" --bytecode \"%hu,", info->bpf_program_num_elem); 117 bpf_print_code(ip, match); 118 printf("\""); 119 } 120 121 static void bpf_fcheck(struct xt_fcheck_call *cb) 122 { 123 if (!(cb->xflags & (1 << O_BCODE_STDIN))) 124 xtables_error(PARAMETER_PROBLEM, 125 "bpf: missing --bytecode parameter"); 126 } 127 128 static void bpf_print(const void *ip, const struct xt_entry_match *match, 129 int numeric) 130 { 131 printf("match bpf "); 132 return bpf_print_code(ip, match); 133 } 134 135 static struct xtables_match bpf_match = { 136 .family = NFPROTO_UNSPEC, 137 .name = "bpf", 138 .version = XTABLES_VERSION, 139 .size = XT_ALIGN(sizeof(struct xt_bpf_info)), 140 .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)), 141 .help = bpf_help, 142 .print = bpf_print, 143 .save = bpf_save, 144 .x6_parse = bpf_parse, 145 .x6_fcheck = bpf_fcheck, 146 .x6_options = bpf_opts, 147 }; 148 149 void _init(void) 150 { 151 xtables_register_match(&bpf_match); 152 } 153