changing trunk/trunk to trunk
[iptables.git] / extensions / libxt_connlimit.c
1 /* Shared library add-on to iptables to add connection limit 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 "../include/linux/netfilter/xt_connlimit.h"
10
11 static void connlimit_help(void)
12 {
13         printf(
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");
18 }
19
20 static const struct option connlimit_opts[] = {
21         {"connlimit-above", 1, NULL, 'A'},
22         {"connlimit-mask",  1, NULL, 'M'},
23         { .name = NULL }
24 };
25
26 static void connlimit_init(struct xt_entry_match *match)
27 {
28         struct xt_connlimit_info *info = (void *)match->data;
29         info->v4_mask = 0xFFFFFFFFUL;
30 }
31
32 static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len)
33 {
34         if (prefix_len == 0) {
35                 mask[0] = mask[1] = mask[2] = mask[3] = 0;
36         } else if (prefix_len <= 32) {
37                 mask[0] <<= 32 - prefix_len;
38                 mask[1] = mask[2] = mask[3] = 0;
39         } else if (prefix_len <= 64) {
40                 mask[1] <<= 32 - (prefix_len - 32);
41                 mask[2] = mask[3] = 0;
42         } else if (prefix_len <= 96) {
43                 mask[2] <<= 32 - (prefix_len - 64);
44                 mask[3] = 0;
45         } else if (prefix_len <= 128) {
46                 mask[3] <<= 32 - (prefix_len - 96);
47         }
48         mask[0] = htonl(mask[0]);
49         mask[1] = htonl(mask[1]);
50         mask[2] = htonl(mask[2]);
51         mask[3] = htonl(mask[3]);
52 }
53
54 static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags,
55                            struct xt_connlimit_info *info, unsigned int family)
56 {
57         char *err;
58         int i;
59
60         switch (c) {
61         case 'A':
62                 if (*flags & 0x1)
63                         exit_error(PARAMETER_PROBLEM,
64                                 "--connlimit-above may be given only once");
65                 *flags |= 0x1;
66                 check_inverse(optarg, &invert, &optind, 0);
67                 info->limit   = strtoul(argv[optind-1], NULL, 0);
68                 info->inverse = invert;
69                 break;
70         case 'M':
71                 if (*flags & 0x2)
72                         exit_error(PARAMETER_PROBLEM,
73                                 "--connlimit-mask may be given only once");
74
75                 *flags |= 0x2;
76                 i = strtoul(argv[optind-1], &err, 0);
77                 if (family == AF_INET6) {
78                         if (i > 128 || *err != '\0')
79                                 exit_error(PARAMETER_PROBLEM,
80                                         "--connlimit-mask must be between "
81                                         "0 and 128");
82                         prefix_to_netmask(info->v6_mask, i);
83                 } else {
84                         if (i > 32 || *err != '\0')
85                                 exit_error(PARAMETER_PROBLEM,
86                                         "--connlimit-mask must be between "
87                                         "0 and 32");
88                         if (i == 0)
89                                 info->v4_mask = 0;
90                         else
91                                 info->v4_mask = htonl(0xFFFFFFFF << (32 - i));
92                 }
93                 break;
94         default:
95                 return 0;
96         }
97
98         return 1;
99 }
100
101 static int connlimit_parse4(int c, char **argv, int invert,
102                             unsigned int *flags, const void *entry,
103                             struct xt_entry_match **match)
104 {
105         return connlimit_parse(c, argv, invert, flags,
106                (void *)(*match)->data, AF_INET);
107 }
108
109 static int connlimit_parse6(int c, char **argv, int invert,
110                             unsigned int *flags, const void *entry,
111                             struct xt_entry_match **match)
112 {
113         return connlimit_parse(c, argv, invert, flags,
114                (void *)(*match)->data, AF_INET6);
115 }
116
117 static void connlimit_check(unsigned int flags)
118 {
119         if (!(flags & 0x1))
120                 exit_error(PARAMETER_PROBLEM,
121                         "You must specify \"--connlimit-above\"");
122 }
123
124 static unsigned int count_bits4(u_int32_t mask)
125 {
126         unsigned int bits = 0;
127
128         for (mask = ~ntohl(mask); mask != 0; mask >>= 1)
129                 ++bits;
130
131         return 32 - bits;
132 }
133
134 static unsigned int count_bits6(const u_int32_t *mask)
135 {
136         unsigned int bits = 0, i;
137         u_int32_t tmp[4];
138
139         for (i = 0; i < 4; ++i)
140                 for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1)
141                         ++bits;
142         return 128 - bits;
143 }
144
145 static void connlimit_print4(const void *ip,
146                              const struct xt_entry_match *match, int numeric)
147 {
148         const struct xt_connlimit_info *info = (const void *)match->data;
149
150         printf("#conn/%u %s %u ", count_bits4(info->v4_mask),
151                info->inverse ? "<=" : ">", info->limit);
152 }
153
154 static void connlimit_print6(const void *ip,
155                              const struct xt_entry_match *match, int numeric)
156 {
157         const struct xt_connlimit_info *info = (const void *)match->data;
158         printf("#conn/%u %s %u ", count_bits6(info->v6_mask),
159                info->inverse ? "<=" : ">", info->limit);
160 }
161
162 static void connlimit_save4(const void *ip, const struct xt_entry_match *match)
163 {
164         const struct xt_connlimit_info *info = (const void *)match->data;
165
166         printf("%s--connlimit-above %u --connlimit-mask %u ",
167                info->inverse ? "! " : "", info->limit,
168                count_bits4(info->v4_mask));
169 }
170
171 static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
172 {
173         const struct xt_connlimit_info *info = (const void *)match->data;
174
175         printf("%s--connlimit-above %u --connlimit-mask %u ",
176                info->inverse ? "! " : "", info->limit,
177                count_bits6(info->v6_mask));
178 }
179
180 static struct xtables_match connlimit_match = {
181         .name          = "connlimit",
182         .family        = AF_INET,
183         .version       = XTABLES_VERSION,
184         .size          = XT_ALIGN(sizeof(struct xt_connlimit_info)),
185         .userspacesize = offsetof(struct xt_connlimit_info, data),
186         .help          = connlimit_help,
187         .init          = connlimit_init,
188         .parse         = connlimit_parse4,
189         .final_check   = connlimit_check,
190         .print         = connlimit_print4,
191         .save          = connlimit_save4,
192         .extra_opts    = connlimit_opts,
193 };
194
195 static struct xtables_match connlimit_match6 = {
196         .name          = "connlimit",
197         .family        = AF_INET6,
198         .version       = XTABLES_VERSION,
199         .size          = XT_ALIGN(sizeof(struct xt_connlimit_info)),
200         .userspacesize = offsetof(struct xt_connlimit_info, data),
201         .help          = connlimit_help,
202         .init          = connlimit_init,
203         .parse         = connlimit_parse6,
204         .final_check   = connlimit_check,
205         .print         = connlimit_print6,
206         .save          = connlimit_save6,
207         .extra_opts    = connlimit_opts,
208 };
209
210 void _init(void)
211 {
212         xtables_register_match(&connlimit_match);
213         xtables_register_match(&connlimit_match6);
214 }