blob: 574f8f7d6d4647516bca536cc60e3c1f32e5e2cd [file] [log] [blame]
Patrick McHardy10e0fbb2006-08-31 14:01:35 +00001#include <stdio.h>
2#include <netdb.h>
3#include <string.h>
4#include <stdlib.h>
5#include <stddef.h>
6#include <getopt.h>
7
Yasuyuki KOZAKAIdfd78a82007-08-04 08:28:23 +00008#include <xtables.h>
Patrick McHardy10e0fbb2006-08-31 14:01:35 +00009#include <linux/netfilter/xt_statistic.h>
10
Jan Engelhardt181dead2007-10-04 16:27:07 +000011static void statistic_help(void)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000012{
13 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020014"statistic match options:\n"
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000015" --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"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020020" --packet p Initial counter value (0 <= p <= n-1, default 0)\n");
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000021}
22
Jan Engelhardt181dead2007-10-04 16:27:07 +000023static const struct option statistic_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000024 { "mode", 1, NULL, '1' },
25 { "probability", 1, NULL, '2' },
26 { "every", 1, NULL, '3' },
27 { "packet", 1, NULL, '4' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000028 { .name = NULL }
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000029};
30
Jan Engelhardtdbb77542008-02-11 00:33:30 +010031static struct xt_statistic_info *global_info;
32
33static void statistic_mt_init(struct xt_entry_match *match)
34{
35 global_info = (void *)match->data;
36}
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000037
38static int
Jan Engelhardt181dead2007-10-04 16:27:07 +000039statistic_parse(int c, char **argv, int invert, unsigned int *flags,
40 const void *entry, struct xt_entry_match **match)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000041{
Jan Engelhardtdbb77542008-02-11 00:33:30 +010042 struct xt_statistic_info *info = (void *)(*match)->data;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010043 unsigned int val;
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000044 double prob;
45
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000046 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");
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010074 if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX))
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000075 exit_error(PARAMETER_PROBLEM,
76 "cannot parse --every `%s'", optarg);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010077 info->u.nth.every = val;
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000078 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");
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010086 if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX))
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000087 exit_error(PARAMETER_PROBLEM,
88 "cannot parse --packet `%s'", optarg);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010089 info->u.nth.packet = val;
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000090 *flags |= 0x8;
91 break;
92 default:
93 return 0;
94 }
95 return 1;
96}
97
Jan Engelhardt181dead2007-10-04 16:27:07 +000098static void statistic_check(unsigned int flags)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +000099{
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");
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100105 if (flags & 0x2 && global_info->mode != XT_STATISTIC_MODE_RANDOM)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000106 exit_error(PARAMETER_PROBLEM,
107 "--probability can only be used in random mode");
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100108 if (flags & 0x4 && global_info->mode != XT_STATISTIC_MODE_NTH)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000109 exit_error(PARAMETER_PROBLEM,
110 "--every can only be used in nth mode");
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100111 if (flags & 0x8 && global_info->mode != XT_STATISTIC_MODE_NTH)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000112 exit_error(PARAMETER_PROBLEM,
113 "--packet can only be used in nth mode");
Nicolas Bouliane0c6bf102007-07-03 12:52:55 +0000114 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. */
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100118 if (global_info->u.nth.packet > global_info->u.nth.every)
Nicolas Bouliane0c6bf102007-07-03 12:52:55 +0000119 exit_error(PARAMETER_PROBLEM,
120 "the --packet p must be 0 <= p <= n-1");
121
122
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100123 global_info->u.nth.count = global_info->u.nth.every -
124 global_info->u.nth.packet;
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000125}
126
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000127static void print_match(const struct xt_statistic_info *info, char *prefix)
128{
129 if (info->flags & XT_STATISTIC_INVERT)
130 printf("! ");
131
132 switch (info->mode) {
133 case XT_STATISTIC_MODE_RANDOM:
134 printf("%smode random %sprobability %f ", prefix, prefix,
135 1.0 * info->u.random.probability / 0x80000000);
136 break;
137 case XT_STATISTIC_MODE_NTH:
138 printf("%smode nth %severy %u ", prefix, prefix,
139 info->u.nth.every + 1);
140 if (info->u.nth.packet)
141 printf("%spacket %u ", prefix, info->u.nth.packet);
142 break;
143 }
144}
145
146static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000147statistic_print(const void *ip, const struct xt_entry_match *match, int numeric)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000148{
149 struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
150
151 printf("statistic ");
152 print_match(info, "");
153}
154
Jan Engelhardt181dead2007-10-04 16:27:07 +0000155static void statistic_save(const void *ip, const struct xt_entry_match *match)
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000156{
157 struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
158
159 print_match(info, "--");
160}
161
Jan Engelhardt181dead2007-10-04 16:27:07 +0000162static struct xtables_match statistic_match = {
Jan Engelhardt23545c22008-02-14 04:23:04 +0100163 .family = AF_UNSPEC,
Yasuyuki KOZAKAIdfd78a82007-08-04 08:28:23 +0000164 .name = "statistic",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200165 .version = XTABLES_VERSION,
Yasuyuki KOZAKAIdfd78a82007-08-04 08:28:23 +0000166 .size = XT_ALIGN(sizeof(struct xt_statistic_info)),
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000167 .userspacesize = offsetof(struct xt_statistic_info, u.nth.count),
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100168 .init = statistic_mt_init,
Jan Engelhardt181dead2007-10-04 16:27:07 +0000169 .help = statistic_help,
170 .parse = statistic_parse,
171 .final_check = statistic_check,
172 .print = statistic_print,
173 .save = statistic_save,
174 .extra_opts = statistic_opts,
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000175};
176
177void _init(void)
178{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000179 xtables_register_match(&statistic_match);
Patrick McHardy10e0fbb2006-08-31 14:01:35 +0000180}