1/* Shared library add-on to iptables to add state tracking support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <stddef.h>
7#include <getopt.h>
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ip_conntrack.h>
10#include <linux/netfilter_ipv4/ipt_iplimit.h>
11
12/* Function which prints out usage message. */
13static void
14help(void)
15{
16	printf(
17"iplimit v%s options:\n"
18"[!] --iplimit-above n		match if the number of existing tcp connections is (not) above n\n"
19" --iplimit-mask n		group hosts using mask\n"
20"\n", IPTABLES_VERSION);
21}
22
23static struct option opts[] = {
24	{ "iplimit-above", 1, 0, '1' },
25	{ "iplimit-mask",  1, 0, '2' },
26	{0}
27};
28
29/* Initialize the match. */
30static void
31init(struct ipt_entry_match *m, unsigned int *nfcache)
32{
33	/* Can't cache this */
34	*nfcache |= NFC_UNKNOWN;
35}
36
37/* Function which parses command options; returns true if it
38   ate an option */
39static int
40parse(int c, char **argv, int invert, unsigned int *flags,
41      const struct ipt_entry *entry,
42      unsigned int *nfcache,
43      struct ipt_entry_match **match)
44{
45	struct ipt_iplimit_info *info = (struct ipt_iplimit_info*)(*match)->data;
46
47	if (0 == (*flags & 2)) {
48		/* set default mask unless we've already seen a mask option */
49		info->mask = htonl(0xFFFFFFFF);
50	}
51
52	switch (c) {
53	case '1':
54		check_inverse(optarg, &invert, &optind, 0);
55		info->limit = atoi(argv[optind-1]);
56		info->inverse = invert;
57		*flags |= 1;
58		break;
59
60	case '2':
61		info->mask = htonl(0xFFFFFFFF << (32 - atoi(argv[optind-1])));
62		*flags |= 2;
63		break;
64
65	default:
66		return 0;
67	}
68
69	return 1;
70}
71
72/* Final check */
73static void final_check(unsigned int flags)
74{
75	if (!flags & 1)
76		exit_error(PARAMETER_PROBLEM, "You must specify `--iplimit-above'");
77}
78
79static int
80count_bits(u_int32_t mask)
81{
82	int i, bits;
83
84	for (bits = 0, i = 31; i >= 0; i--) {
85		if (mask & htonl((u_int32_t)1 << i)) {
86			bits++;
87			continue;
88		}
89		break;
90	}
91	return bits;
92}
93
94/* Prints out the matchinfo. */
95static void
96print(const struct ipt_ip *ip,
97      const struct ipt_entry_match *match,
98      int numeric)
99{
100	struct ipt_iplimit_info *info = (struct ipt_iplimit_info*)match->data;
101
102	printf("#conn/%d %s %d ", count_bits(info->mask),
103	       info->inverse ? "<" : ">", info->limit);
104}
105
106/* Saves the matchinfo in parsable form to stdout. */
107static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
108{
109	struct ipt_iplimit_info *info = (struct ipt_iplimit_info*)match->data;
110
111	printf("%s--iplimit-above %d ",info->inverse ? "! " : "",info->limit);
112	printf("--iplimit-mask %d ",count_bits(info->mask));
113}
114
115static struct iptables_match iplimit = {
116	name:		"iplimit",
117	version:	IPTABLES_VERSION,
118	size:		IPT_ALIGN(sizeof(struct ipt_iplimit_info)),
119	userspacesize:	offsetof(struct ipt_iplimit_info,data),
120	help:		help,
121	init:		init,
122	parse:		parse,
123	final_check:	final_check,
124	print:		print,
125	save: 		save,
126	extra_opts:	opts
127};
128
129void _init(void)
130{
131	register_match(&iplimit);
132}
133