iptables-1.3.2-20050720
[iptables.git] / extensions / libipt_random.c
1 /* 
2    Shared library add-on to iptables to add match support for random match.
3    
4    This file is distributed under the terms of the GNU General Public
5    License (GPL). Copies of the GPL can be obtained from:
6    ftp://prep.ai.mit.edu/pub/gnu/GPL
7
8    2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial development.
9 */
10
11 #include <stdio.h>
12 #include <netdb.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <syslog.h>
16 #include <getopt.h>
17 #include <iptables.h>
18 #include <linux/netfilter_ipv4/ip_tables.h>
19 #include <linux/netfilter_ipv4/ipt_random.h>
20
21 /**
22  * The kernel random routing returns numbers between 0 and 255.
23  * To ease the task of the user in choosing the probability
24  * of matching, we want him to be able to use percentages.
25  * Therefore we have to accept numbers in percentage here,
26  * turn them into number between 0 and 255 for the kernel module,
27  * and turn them back to percentages when we print/save
28  * the rule.
29  */
30
31
32 /* Function which prints out usage message. */
33 static void
34 help(void)
35 {
36         printf(
37 "random v%s options:\n"
38 "  [--average      percent ]    The probability in percentage of the match\n"
39 "                               If ommited, a probability of 50%% percent is set.\n"
40 "                               Percentage must be within : 1 <= percent <= 99.\n\n",
41 IPTABLES_VERSION);
42 }
43
44 static struct option opts[] = {
45         { "average", 1, 0, '1' },
46         { 0 }
47 };
48
49 /* Initialize the target. */
50 static void
51 init(struct ipt_entry_match *m, unsigned int *nfcache)
52 {
53         struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(m)->data;
54
55         /* We assign the average to be 50 which is our default value */
56         /* 50 * 2.55 = 128 */
57         randinfo->average = 128;
58 }
59
60 #define IPT_RAND_OPT_AVERAGE    0x01
61
62 /* Function which parses command options; returns true if it
63    ate an option */
64 static int
65 parse(int c, char **argv, int invert, unsigned int *flags,
66       const struct ipt_entry *entry,
67       unsigned int *nfcache,
68       struct ipt_entry_match **match)
69 {
70         struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(*match)->data;
71         unsigned int num;
72
73         switch (c) {
74         case '1':
75                 /* check for common mistakes... */
76                 if (invert)
77                         exit_error(PARAMETER_PROBLEM,
78                                    "Can't specify ! --average");
79                 if (*flags & IPT_RAND_OPT_AVERAGE)
80                         exit_error(PARAMETER_PROBLEM,
81                                    "Can't specify --average twice");
82
83                 /* Remember, this function will interpret a leading 0 to be 
84                    Octal, a leading 0x to be hexdecimal... */
85                 if (string_to_number(optarg, 1, 99, &num) == -1 || num < 1)
86                         exit_error(PARAMETER_PROBLEM,
87                                    "bad --average `%s', must be between 1 and 99", optarg);
88
89                 /* assign the values */
90                 randinfo->average = (int)(num * 2.55);
91                 *flags |= IPT_RAND_OPT_AVERAGE;
92                 break;
93         default:
94                 return 0;
95         }
96         return 1;
97 }
98
99 /* Final check; nothing. */
100 static void final_check(unsigned int flags)
101 {
102 }
103
104 /* Prints out the targinfo. */
105 static void
106 print(const struct ipt_ip *ip,
107       const struct ipt_entry_match *match,
108       int numeric)
109 {
110         const struct ipt_rand_info *randinfo
111                 = (const struct ipt_rand_info *)match->data;
112         div_t result = div((randinfo->average*100), 255);
113         if (result.rem > 127)  /* round up... */
114                 ++result.quot;
115
116         printf(" random %u%% ", result.quot);
117 }
118
119 /* Saves the union ipt_targinfo in parsable form to stdout. */
120 static void
121 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
122 {
123         const struct ipt_rand_info *randinfo
124                 = (const struct ipt_rand_info *)match->data;
125         div_t result = div((randinfo->average *100), 255);
126         if (result.rem > 127)  /* round up... */
127                 ++result.quot;
128
129         printf("--average %u ", result.quot);
130 }
131
132 struct iptables_match rand_match = { 
133         .next           = NULL,
134         .name           = "random",
135         .version        = IPTABLES_VERSION,
136         .size           = IPT_ALIGN(sizeof(struct ipt_rand_info)),
137         .userspacesize  = IPT_ALIGN(sizeof(struct ipt_rand_info)),
138         .help           = &help,
139         .init           = &init,
140         .parse          = &parse,
141         .final_check    = &final_check,
142         .print          = &print,
143         .save           = &save,
144         .extra_opts     = opts
145 };
146
147 void _init(void)
148 {
149         register_match(&rand_match);
150 }