fix for f12, gcc4.4
[iptables.git] / extensions / libipt_statistic.c
1 #include <stdio.h>
2 #include <netdb.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stddef.h>
6 #include <getopt.h>
7
8 #include <iptables.h>
9 #include <linux/netfilter/xt_statistic.h>
10
11 static void
12 help(void)
13 {
14         printf(
15 "statistic match v%s options:\n"
16 " --mode mode                    Match mode (random, nth)\n"
17 " random mode:\n"
18 " --probability p                Probability\n"
19 " nth mode:\n"
20 " --every n                      Match every nth packet\n"
21 " --packet p                     Initial counter value (0 <= p <= n-1, default 0)\n"
22 "\n",
23 IPTABLES_VERSION);
24 }
25
26 static struct option opts[] = {
27         { "mode", 1, 0, '1' },
28         { "probability", 1, 0, '2' },
29         { "every", 1, 0, '3' },
30         { "packet", 1, 0, '4' },
31         { 0 }
32 };
33
34 static struct xt_statistic_info *info;
35
36 static int
37 parse(int c, char **argv, int invert, unsigned int *flags,
38       const struct ipt_entry *entry,
39       unsigned int *nfcache,
40       struct ipt_entry_match **match)
41 {
42         double prob;
43
44         info = (void *)(*match)->data;
45
46         if (invert)
47                 info->flags |= XT_STATISTIC_INVERT;
48
49         switch (c) {
50         case '1':
51                 if (*flags & 0x1)
52                         exit_error(PARAMETER_PROBLEM, "double --mode");
53                 if (!strcmp(optarg, "random"))
54                         info->mode = XT_STATISTIC_MODE_RANDOM;
55                 else if (!strcmp(optarg, "nth"))
56                         info->mode = XT_STATISTIC_MODE_NTH;
57                 else
58                         exit_error(PARAMETER_PROBLEM, "Bad mode `%s'", optarg);
59                 *flags |= 0x1;
60                 break;
61         case '2':
62                 if (*flags & 0x2)
63                         exit_error(PARAMETER_PROBLEM, "double --probability");
64                 prob = atof(optarg);
65                 if (prob < 0 || prob > 1)
66                         exit_error(PARAMETER_PROBLEM,
67                                    "--probability must be between 0 and 1");
68                 info->u.random.probability = 0x80000000 * prob;
69                 *flags |= 0x2;
70                 break;
71         case '3':
72                 if (*flags & 0x4)
73                         exit_error(PARAMETER_PROBLEM, "double --every");
74                 if (string_to_number(optarg, 0, 0xFFFFFFFF,
75                                      &info->u.nth.every) == -1)
76                         exit_error(PARAMETER_PROBLEM,
77                                    "cannot parse --every `%s'", optarg);
78                 if (info->u.nth.every == 0)
79                         exit_error(PARAMETER_PROBLEM, "--every cannot be 0");
80                 info->u.nth.every--;
81                 *flags |= 0x4;
82                 break;
83         case '4':
84                 if (*flags & 0x8)
85                         exit_error(PARAMETER_PROBLEM, "double --packet");
86                 if (string_to_number(optarg, 0, 0xFFFFFFFF,
87                                      &info->u.nth.packet) == -1)
88                         exit_error(PARAMETER_PROBLEM,
89                                    "cannot parse --packet `%s'", optarg);
90                 *flags |= 0x8;
91                 break;
92         default:
93                 return 0;
94         }
95         return 1;
96 }
97
98 /* Final check; must have specified --mark. */
99 static void
100 final_check(unsigned int flags)
101 {
102         if (!(flags & 0x1))
103                 exit_error(PARAMETER_PROBLEM, "no mode specified");
104         if ((flags & 0x2) && (flags & (0x4 | 0x8)))
105                 exit_error(PARAMETER_PROBLEM,
106                            "both nth and random parameters given");
107         if (flags & 0x2 && info->mode != XT_STATISTIC_MODE_RANDOM)
108                 exit_error(PARAMETER_PROBLEM,
109                            "--probability can only be used in random mode");
110         if (flags & 0x4 && info->mode != XT_STATISTIC_MODE_NTH)
111                 exit_error(PARAMETER_PROBLEM,
112                            "--every can only be used in nth mode");
113         if (flags & 0x8 && info->mode != XT_STATISTIC_MODE_NTH)
114                 exit_error(PARAMETER_PROBLEM,
115                            "--packet can only be used in nth mode");
116         info->u.nth.count = info->u.nth.every - info->u.nth.packet;
117 }
118
119 /* Prints out the matchinfo. */
120 static void print_match(const struct xt_statistic_info *info, char *prefix)
121 {
122         if (info->flags & XT_STATISTIC_INVERT)
123                 printf("! ");
124
125         switch (info->mode) {
126         case XT_STATISTIC_MODE_RANDOM:
127                 printf("%smode random %sprobability %f ", prefix, prefix,
128                        1.0 * info->u.random.probability / 0x80000000);
129                 break;
130         case XT_STATISTIC_MODE_NTH:
131                 printf("%smode nth %severy %u ", prefix, prefix,
132                        info->u.nth.every + 1);
133                 if (info->u.nth.packet)
134                         printf("%spacket %u ", prefix, info->u.nth.packet);
135                 break;
136         }
137 }
138
139 static void
140 print(const struct ipt_ip *ip,
141       const struct ipt_entry_match *match,
142       int numeric)
143 {
144         struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
145
146         printf("statistic ");
147         print_match(info, "");
148 }
149
150 /* Saves the union ipt_matchinfo in parsable form to stdout. */
151 static void
152 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
153 {
154         struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
155
156         print_match(info, "--");
157 }
158
159 static struct iptables_match statistic = { 
160         .name           = "statistic",
161         .version        = IPTABLES_VERSION,
162         .size           = IPT_ALIGN(sizeof(struct xt_statistic_info)),
163         .userspacesize  = offsetof(struct xt_statistic_info, u.nth.count),
164         .help           = help,
165         .parse          = parse,
166         .final_check    = final_check,
167         .print          = print,
168         .save           = save,
169         .extra_opts     = opts
170 };
171
172 void _init(void)
173 {
174         register_match(&statistic);
175 }