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   2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 port.
10*/
11
12#include <stdio.h>
13#include <netdb.h>
14#include <string.h>
15#include <stdlib.h>
16#include <syslog.h>
17#include <getopt.h>
18#include <ip6tables.h>
19#include <linux/netfilter_ipv6/ip6_tables.h>
20#include <linux/netfilter_ipv6/ip6t_random.h>
21
22/**
23 * The kernel random routing returns numbers between 0 and 255.
24 * To ease the task of the user in choosing the probability
25 * of matching, we want him to be able to use percentages.
26 * Therefore we have to accept numbers in percentage here,
27 * turn them into number between 0 and 255 for the kernel module,
28 * and turn them back to percentages when we print/save
29 * the rule.
30 */
31
32
33/* Function which prints out usage message. */
34static void
35help(void)
36{
37	printf(
38"random v%s options:\n"
39"  [--average]     percent      The probability in percentage of the match\n"
40"                               If ommited, a probability of 50%% percent is set.\n"
41"                               Percentage must be within : 1 <= percent <= 99.\n\n",
42IPTABLES_VERSION);
43}
44
45static struct option opts[] = {
46	{ "average", 1, 0, '1' },
47	{ 0 }
48};
49
50/* Initialize the target. */
51static void
52init(struct ip6t_entry_match *m, unsigned int *nfcache)
53{
54	struct ip6t_rand_info *randinfo = (struct ip6t_rand_info *)(m)->data;
55
56	/* We assign the average to be 50 which is our default value */
57	/* 50 * 2.55 = 128 */
58	randinfo->average = 128;
59}
60
61#define IP6T_RAND_OPT_AVERAGE	0x01
62
63/* Function which parses command options; returns true if it
64   ate an option */
65static int
66parse(int c, char **argv, int invert, unsigned int *flags,
67      const struct ip6t_entry *entry,
68      unsigned int *nfcache,
69      struct ip6t_entry_match **match)
70{
71	struct ip6t_rand_info *randinfo = (struct ip6t_rand_info *)(*match)->data;
72	unsigned int num;
73
74	switch (c) {
75	case '1':
76		/* check for common mistakes... */
77		if (invert)
78			exit_error(PARAMETER_PROBLEM,
79				   "Can't specify ! --average");
80		if (*flags & IP6T_RAND_OPT_AVERAGE)
81			exit_error(PARAMETER_PROBLEM,
82				   "Can't specify --average twice");
83
84		/* Remember, this function will interpret a leading 0 to be
85		   Octal, a leading 0x to be hexdecimal... */
86                if (string_to_number(optarg, 1, 99, &num) == -1 || num < 1)
87                        exit_error(PARAMETER_PROBLEM,
88                                   "bad --average `%s', must be between 1 and 99", optarg);
89
90		/* assign the values */
91		randinfo->average = (int)(num * 2.55);
92		*flags |= IP6T_RAND_OPT_AVERAGE;
93		break;
94	default:
95		return 0;
96	}
97	return 1;
98}
99
100/* Final check; nothing. */
101static void final_check(unsigned int flags)
102{
103}
104
105/* Prints out the targinfo. */
106static void
107print(const struct ip6t_ip6 *ip,
108      const struct ip6t_entry_match *match,
109      int numeric)
110{
111	const struct ip6t_rand_info *randinfo
112		= (const struct ip6t_rand_info *)match->data;
113	div_t result = div((randinfo->average*100), 255);
114	if (result.rem > 127)  /* round up... */
115		++result.quot;
116
117	printf(" random %u%% ", result.quot);
118}
119
120/* Saves the union ip6t_targinfo in parsable form to stdout. */
121static void
122save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
123{
124	const struct ip6t_rand_info *randinfo
125		= (const struct ip6t_rand_info *)match->data;
126	div_t result = div((randinfo->average *100), 255);
127	if (result.rem > 127)  /* round up... */
128		++result.quot;
129
130	printf("--average %u ", result.quot);
131}
132
133struct ip6tables_match rand_match = {
134	.name		= "random",
135	.version	= IPTABLES_VERSION,
136	.size		= IP6T_ALIGN(sizeof(struct ip6t_rand_info)),
137	.userspacesize	= IP6T_ALIGN(sizeof(struct ip6t_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
147void _init(void)
148{
149	register_match6(&rand_match);
150}
151