blob: 64faa8f1fdc8b78e9e61a89b2a3ccb91110b09be [file] [log] [blame]
/* Shared library add-on to iptables to add byte tracking support. */
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/xt_connbytes.h>
/* Function which prints out usage message. */
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 option connbytes_opts[] = {
{ "connbytes", 1, NULL, '1' },
{ "connbytes-dir", 1, NULL, '2' },
{ "connbytes-mode", 1, NULL, '3' },
{ .name = NULL }
};
static void
parse_range(const char *arg, struct xt_connbytes_info *si)
{
char *colon,*p;
si->count.from = strtoul(arg,&colon,10);
if (*colon != ':')
exit_error(PARAMETER_PROBLEM, "Bad range `%s'", arg);
si->count.to = strtoul(colon+1,&p,10);
if (p == colon+1) {
/* second number omited */
si->count.to = 0xffffffff;
}
if (si->count.from > si->count.to)
exit_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
(unsigned long long)si->count.from,
(unsigned long long)si->count.to);
}
/* Function which parses command options; returns true if it
ate an option */
static int
connbytes_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data;
unsigned long i;
switch (c) {
case '1':
if (check_inverse(optarg, &invert, &optind, 0))
optind++;
parse_range(argv[optind-1], sinfo);
if (invert) {
i = sinfo->count.from;
sinfo->count.from = sinfo->count.to;
sinfo->count.to = i;
}
*flags |= 1;
break;
case '2':
if (!strcmp(optarg, "original"))
sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
else if (!strcmp(optarg, "reply"))
sinfo->direction = XT_CONNBYTES_DIR_REPLY;
else if (!strcmp(optarg, "both"))
sinfo->direction = XT_CONNBYTES_DIR_BOTH;
else
exit_error(PARAMETER_PROBLEM,
"Unknown --connbytes-dir `%s'", optarg);
*flags |= 2;
break;
case '3':
if (!strcmp(optarg, "packets"))
sinfo->what = XT_CONNBYTES_PKTS;
else if (!strcmp(optarg, "bytes"))
sinfo->what = XT_CONNBYTES_BYTES;
else if (!strcmp(optarg, "avgpkt"))
sinfo->what = XT_CONNBYTES_AVGPKT;
else
exit_error(PARAMETER_PROBLEM,
"Unknown --connbytes-mode `%s'", optarg);
*flags |= 4;
break;
default:
return 0;
}
return 1;
}
static void connbytes_check(unsigned int flags)
{
if (flags != 7)
exit_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
"`--connbytes-dir' and `--connbytes-mode'");
}
static void print_mode(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(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;
}
}
/* Prints out the matchinfo. */
static void
connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)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);
}
/* Saves the matchinfo in parsable form to stdout. */
static void connbytes_save(const void *ip, const struct xt_entry_match *match)
{
struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)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 = AF_INET,
.name = "connbytes",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_connbytes_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)),
.help = connbytes_help,
.parse = connbytes_parse,
.final_check = connbytes_check,
.print = connbytes_print,
.save = connbytes_save,
.extra_opts = connbytes_opts,
};
static struct xtables_match connbytes_match6 = {
.family = AF_INET6,
.name = "connbytes",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_connbytes_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)),
.help = connbytes_help,
.parse = connbytes_parse,
.final_check = connbytes_check,
.print = connbytes_print,
.save = connbytes_save,
.extra_opts = connbytes_opts,
};
void _init(void)
{
xtables_register_match(&connbytes_match);
xtables_register_match(&connbytes_match6);
}