1 /* Shared library add-on to iptables to add connection limit support. */
9 #include <linux/netfilter/xt_connlimit.h>
11 static void connlimit_help(void)
14 "connlimit match options:\n"
15 "[!] --connlimit-above n match if the number of existing "
16 " connections is (not) above n\n"
17 " --connlimit-mask n group hosts using mask\n");
20 static const struct option connlimit_opts[] = {
21 {"connlimit-above", 1, NULL, 'A'},
22 {"connlimit-mask", 1, NULL, 'M'},
26 static void connlimit_init(struct xt_entry_match *match)
28 struct xt_connlimit_info *info = (void *)match->data;
30 /* This will also initialize the v4 mask correctly */
31 memset(info->v6_mask, 0xFF, sizeof(info->v6_mask));
34 static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len)
36 if (prefix_len == 0) {
37 mask[0] = mask[1] = mask[2] = mask[3] = 0;
38 } else if (prefix_len <= 32) {
39 mask[0] <<= 32 - prefix_len;
40 mask[1] = mask[2] = mask[3] = 0;
41 } else if (prefix_len <= 64) {
42 mask[1] <<= 32 - (prefix_len - 32);
43 mask[2] = mask[3] = 0;
44 } else if (prefix_len <= 96) {
45 mask[2] <<= 32 - (prefix_len - 64);
47 } else if (prefix_len <= 128) {
48 mask[3] <<= 32 - (prefix_len - 96);
50 mask[0] = htonl(mask[0]);
51 mask[1] = htonl(mask[1]);
52 mask[2] = htonl(mask[2]);
53 mask[3] = htonl(mask[3]);
56 static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags,
57 struct xt_connlimit_info *info, unsigned int family)
65 xtables_error(PARAMETER_PROBLEM,
66 "--connlimit-above may be given only once");
68 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
69 info->limit = strtoul(optarg, NULL, 0);
70 info->inverse = invert;
74 xtables_error(PARAMETER_PROBLEM,
75 "--connlimit-mask may be given only once");
78 i = strtoul(optarg, &err, 0);
79 if (family == NFPROTO_IPV6) {
80 if (i > 128 || *err != '\0')
81 xtables_error(PARAMETER_PROBLEM,
82 "--connlimit-mask must be between "
84 prefix_to_netmask(info->v6_mask, i);
86 if (i > 32 || *err != '\0')
87 xtables_error(PARAMETER_PROBLEM,
88 "--connlimit-mask must be between "
93 info->v4_mask = htonl(0xFFFFFFFF << (32 - i));
103 static int connlimit_parse4(int c, char **argv, int invert,
104 unsigned int *flags, const void *entry,
105 struct xt_entry_match **match)
107 return connlimit_parse(c, argv, invert, flags,
108 (void *)(*match)->data, NFPROTO_IPV4);
111 static int connlimit_parse6(int c, char **argv, int invert,
112 unsigned int *flags, const void *entry,
113 struct xt_entry_match **match)
115 return connlimit_parse(c, argv, invert, flags,
116 (void *)(*match)->data, NFPROTO_IPV6);
119 static void connlimit_check(unsigned int flags)
122 xtables_error(PARAMETER_PROBLEM,
123 "You must specify \"--connlimit-above\"");
126 static unsigned int count_bits4(u_int32_t mask)
128 unsigned int bits = 0;
130 for (mask = ~ntohl(mask); mask != 0; mask >>= 1)
136 static unsigned int count_bits6(const u_int32_t *mask)
138 unsigned int bits = 0, i;
141 for (i = 0; i < 4; ++i)
142 for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1)
147 static void connlimit_print4(const void *ip,
148 const struct xt_entry_match *match, int numeric)
150 const struct xt_connlimit_info *info = (const void *)match->data;
152 printf("#conn/%u %s %u ", count_bits4(info->v4_mask),
153 info->inverse ? "<=" : ">", info->limit);
156 static void connlimit_print6(const void *ip,
157 const struct xt_entry_match *match, int numeric)
159 const struct xt_connlimit_info *info = (const void *)match->data;
160 printf("#conn/%u %s %u ", count_bits6(info->v6_mask),
161 info->inverse ? "<=" : ">", info->limit);
164 static void connlimit_save4(const void *ip, const struct xt_entry_match *match)
166 const struct xt_connlimit_info *info = (const void *)match->data;
168 printf("%s--connlimit-above %u --connlimit-mask %u ",
169 info->inverse ? "! " : "", info->limit,
170 count_bits4(info->v4_mask));
173 static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
175 const struct xt_connlimit_info *info = (const void *)match->data;
177 printf("%s--connlimit-above %u --connlimit-mask %u ",
178 info->inverse ? "! " : "", info->limit,
179 count_bits6(info->v6_mask));
182 static struct xtables_match connlimit_mt_reg[] = {
185 .family = NFPROTO_IPV4,
186 .version = XTABLES_VERSION,
187 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
188 .userspacesize = offsetof(struct xt_connlimit_info, data),
189 .help = connlimit_help,
190 .init = connlimit_init,
191 .parse = connlimit_parse4,
192 .final_check = connlimit_check,
193 .print = connlimit_print4,
194 .save = connlimit_save4,
195 .extra_opts = connlimit_opts,
199 .family = NFPROTO_IPV6,
200 .version = XTABLES_VERSION,
201 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)),
202 .userspacesize = offsetof(struct xt_connlimit_info, data),
203 .help = connlimit_help,
204 .init = connlimit_init,
205 .parse = connlimit_parse6,
206 .final_check = connlimit_check,
207 .print = connlimit_print6,
208 .save = connlimit_save6,
209 .extra_opts = connlimit_opts,
215 xtables_register_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg));