summaryrefslogtreecommitdiffstats
path: root/extensions/libipt_random.c
blob: d28ab8ce97cc59761e1fd22b563a3b966492c07c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* 
   Shared library add-on to iptables to add match support for random match.
   
   This file is distributed under the terms of the GNU General Public
   License (GPL). Copies of the GPL can be obtained from:
   ftp://prep.ai.mit.edu/pub/gnu/GPL

   2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial development.
*/

#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
#include <getopt.h>
#include <iptables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_random.h>

/**
 * The kernel random routing returns numbers between 0 and 255.
 * To ease the task of the user in choosing the probability
 * of matching, we want him to be able to use percentages.
 * Therefore we have to accept numbers in percentage here,
 * turn them into number between 0 and 255 for the kernel module,
 * and turn them back to percentages when we print/save
 * the rule.
 */


/* Function which prints out usage message. */
static void
help(void)
{
	printf(
"random v%s options:\n"
"  [--average      percent ]    The probability in percentage of the match\n"
"                               If ommited, a probability of 50%% percent is set.\n"
"                               Percentage must be within : 1 <= percent <= 99.\n\n",
IPTABLES_VERSION);
}

static struct option opts[] = {
	{ "average", 1, 0, '1' },
	{ 0 }
};

/* Initialize the target. */
static void
init(struct ipt_entry_match *m, unsigned int *nfcache)
{
	struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(m)->data;

	/* We assign the average to be 50 which is our default value */
	/* 50 * 2.55 = 128 */
	randinfo->average = 128;
}

#define IPT_RAND_OPT_AVERAGE	0x01

/* Function which parses command options; returns true if it
   ate an option */
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)
{
	struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(*match)->data;
	unsigned int num;

	switch (c) {
	case '1':
		/* check for common mistakes... */
		if (invert)
			exit_error(PARAMETER_PROBLEM,
				   "Can't specify ! --average");
		if (*flags & IPT_RAND_OPT_AVERAGE)
			exit_error(PARAMETER_PROBLEM,
				   "Can't specify --average twice");

		/* Remember, this function will interpret a leading 0 to be 
		   Octal, a leading 0x to be hexdecimal... */
                if (string_to_number(optarg, 1, 99, &num) == -1 || num < 1)
                        exit_error(PARAMETER_PROBLEM,
                                   "bad --average `%s', must be between 1 and 99", optarg);

		/* assign the values */
		randinfo->average = (int)(num * 2.55);
		*flags |= IPT_RAND_OPT_AVERAGE;
		break;
	default:
		return 0;
	}
	return 1;
}

/* Final check; nothing. */
static void final_check(unsigned int flags)
{
}

/* Prints out the targinfo. */
static void
print(const struct ipt_ip *ip,
      const struct ipt_entry_match *match,
      int numeric)
{
	const struct ipt_rand_info *randinfo
		= (const struct ipt_rand_info *)match->data;
	div_t result = div((randinfo->average*100), 255);
	if (result.rem > 127)  /* round up... */
		++result.quot;

	printf(" random %u%% ", result.quot);
}

/* Saves the union ipt_targinfo in parsable form to stdout. */
static void
save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
	const struct ipt_rand_info *randinfo
		= (const struct ipt_rand_info *)match->data;
	div_t result = div((randinfo->average *100), 255);
	if (result.rem > 127)  /* round up... */
		++result.quot;

	printf("--average %u ", result.quot);
}

struct iptables_match rand_match = { 
	.next		= NULL,
	.name		= "random",
	.version	= IPTABLES_VERSION,
	.size		= IPT_ALIGN(sizeof(struct ipt_rand_info)),
	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_rand_info)),
	.help		= &help,
	.init		= &init,
	.parse		= &parse,
	.final_check	= &final_check,
	.print		= &print,
	.save		= &save,
	.extra_opts	= opts
};

void _init(void)
{
	register_match(&rand_match);
}