Home | History | Annotate | Download | only in extensions
      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