#include <stdio.h> #include <string.h> #include <xtables.h> #include <linux/netfilter/xt_connbytes.h> enum { O_CONNBYTES = 0, O_CONNBYTES_DIR, O_CONNBYTES_MODE, }; static void connbytes_help(void) { printf( "connbytes match options:\n" " [!] --connbytes from:[to]\n" " --connbytes-dir [original, reply, both]\n" " --connbytes-mode [packets, bytes, avgpkt]\n"); } static const struct xt_option_entry connbytes_opts[] = { {.name = "connbytes", .id = O_CONNBYTES, .type = XTTYPE_UINT64RC, .flags = XTOPT_MAND | XTOPT_INVERT}, {.name = "connbytes-dir", .id = O_CONNBYTES_DIR, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, {.name = "connbytes-mode", .id = O_CONNBYTES_MODE, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, XTOPT_TABLEEND, }; static void connbytes_parse(struct xt_option_call *cb) { struct xt_connbytes_info *sinfo = cb->data; unsigned long long i; xtables_option_parse(cb); switch (cb->entry->id) { case O_CONNBYTES: sinfo->count.from = cb->val.u64_range[0]; sinfo->count.to = cb->val.u64_range[0]; if (cb->nvals == 2) sinfo->count.to = cb->val.u64_range[1]; if (cb->invert) { i = sinfo->count.from; sinfo->count.from = sinfo->count.to; sinfo->count.to = i; } break; case O_CONNBYTES_DIR: if (strcmp(cb->arg, "original") == 0) sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL; else if (strcmp(cb->arg, "reply") == 0) sinfo->direction = XT_CONNBYTES_DIR_REPLY; else if (strcmp(cb->arg, "both") == 0) sinfo->direction = XT_CONNBYTES_DIR_BOTH; else xtables_error(PARAMETER_PROBLEM, "Unknown --connbytes-dir `%s'", cb->arg); break; case O_CONNBYTES_MODE: if (strcmp(cb->arg, "packets") == 0) sinfo->what = XT_CONNBYTES_PKTS; else if (strcmp(cb->arg, "bytes") == 0) sinfo->what = XT_CONNBYTES_BYTES; else if (strcmp(cb->arg, "avgpkt") == 0) sinfo->what = XT_CONNBYTES_AVGPKT; else xtables_error(PARAMETER_PROBLEM, "Unknown --connbytes-mode `%s'", cb->arg); break; } } static void print_mode(const struct xt_connbytes_info *sinfo) { switch (sinfo->what) { case XT_CONNBYTES_PKTS: fputs(" packets", stdout); break; case XT_CONNBYTES_BYTES: fputs(" bytes", stdout); break; case XT_CONNBYTES_AVGPKT: fputs(" avgpkt", stdout); break; default: fputs(" unknown", stdout); break; } } static void print_direction(const struct xt_connbytes_info *sinfo) { switch (sinfo->direction) { case XT_CONNBYTES_DIR_ORIGINAL: fputs(" original", stdout); break; case XT_CONNBYTES_DIR_REPLY: fputs(" reply", stdout); break; case XT_CONNBYTES_DIR_BOTH: fputs(" both", stdout); break; default: fputs(" unknown", stdout); break; } } static void connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_connbytes_info *sinfo = (const void *)match->data; if (sinfo->count.from > sinfo->count.to) printf(" connbytes ! %llu:%llu", (unsigned long long)sinfo->count.to, (unsigned long long)sinfo->count.from); else printf(" connbytes %llu:%llu", (unsigned long long)sinfo->count.from, (unsigned long long)sinfo->count.to); fputs(" connbytes mode", stdout); print_mode(sinfo); fputs(" connbytes direction", stdout); print_direction(sinfo); } static void connbytes_save(const void *ip, const struct xt_entry_match *match) { const struct xt_connbytes_info *sinfo = (const void *)match->data; if (sinfo->count.from > sinfo->count.to) printf(" ! --connbytes %llu:%llu", (unsigned long long)sinfo->count.to, (unsigned long long)sinfo->count.from); else printf(" --connbytes %llu:%llu", (unsigned long long)sinfo->count.from, (unsigned long long)sinfo->count.to); fputs(" --connbytes-mode", stdout); print_mode(sinfo); fputs(" --connbytes-dir", stdout); print_direction(sinfo); } static struct xtables_match connbytes_match = { .family = NFPROTO_UNSPEC, .name = "connbytes", .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_connbytes_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)), .help = connbytes_help, .print = connbytes_print, .save = connbytes_save, .x6_parse = connbytes_parse, .x6_options = connbytes_opts, }; void _init(void) { xtables_register_match(&connbytes_match); }