• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
help(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
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,unsigned int * nfcache,struct ipt_entry_match ** match)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
final_check(unsigned int flags)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. */
print_match(const struct xt_statistic_info * info,char * prefix)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
print(const struct ipt_ip * ip,const struct ipt_entry_match * match,int numeric)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
save(const struct ipt_ip * ip,const struct ipt_entry_match * match)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 
ipt_statistic_init(void)172 void ipt_statistic_init(void)
173 {
174 	register_match(&statistic);
175 }
176