| /* 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> | 
 |  | 
 | 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 != ':')  | 
 | 		xtables_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) | 
 | 		xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu", | 
 | 			   (unsigned long long)si->count.from, | 
 | 			   (unsigned long long)si->count.to); | 
 | } | 
 |  | 
 | 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 (xtables_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 | 
 | 			xtables_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 | 
 | 			xtables_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) | 
 | 		xtables_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; | 
 | 	} | 
 | } | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | 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		= NFPROTO_IPV4, | 
 | 	.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		= NFPROTO_IPV6, | 
 | 	.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); | 
 | } |