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