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