152 lines
3.8 KiB
C
152 lines
3.8 KiB
C
/*
|
|
* 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);
|
|
}
|