#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);
}