libxt_cluster.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1/*
2 * (C) 2009 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <stdbool.h>
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <getopt.h>
13#include <stddef.h>
14
15#include <xtables.h>
16#include <linux/netfilter/x_tables.h>
17#include <linux/netfilter/xt_cluster.h>
18
19/* hack to keep for check */
20static unsigned int total_nodes;
21static unsigned int node_mask;
22
23static void
24cluster_help(void)
25{
26	printf(
27"cluster match options:\n"
28"  --cluster-total-nodes <num>		Set number of total nodes in cluster\n"
29"  [!] --cluster-local-node <num>	Set the local node number\n"
30"  [!] --cluster-local-nodemask <num>	Set the local node mask\n"
31"  --cluster-hash-seed <num>		Set seed value of the Jenkins hash\n");
32}
33
34enum {
35	CLUSTER_OPT_TOTAL_NODES,
36	CLUSTER_OPT_LOCAL_NODE,
37	CLUSTER_OPT_NODE_MASK,
38	CLUSTER_OPT_HASH_SEED,
39};
40
41static const struct option cluster_opts[] = {
42	{.name = "cluster-total-nodes",    .has_arg = true, .val = CLUSTER_OPT_TOTAL_NODES},
43	{.name = "cluster-local-node",     .has_arg = true, .val = CLUSTER_OPT_LOCAL_NODE},
44	{.name = "cluster-local-nodemask", .has_arg = true, .val = CLUSTER_OPT_NODE_MASK},
45	{.name = "cluster-hash-seed",      .has_arg = true, .val = CLUSTER_OPT_HASH_SEED},
46	XT_GETOPT_TABLEEND,
47};
48
49static int
50cluster_parse(int c, char **argv, int invert, unsigned int *flags,
51	      const void *entry, struct xt_entry_match **match)
52{
53	struct xt_cluster_match_info *info = (void *)(*match)->data;
54	unsigned int num;
55
56	switch (c) {
57	case CLUSTER_OPT_TOTAL_NODES:
58		if (*flags & (1 << c)) {
59			xtables_error(PARAMETER_PROBLEM,
60				      "Can only specify "
61				      "`--cluster-total-nodes' once");
62		}
63		if (!xtables_strtoui(optarg, NULL, &num, 1,
64				     XT_CLUSTER_NODES_MAX)) {
65			xtables_error(PARAMETER_PROBLEM,
66				      "Unable to parse `%s' in "
67				      "`--cluster-total-nodes'", optarg);
68		}
69		total_nodes = num;
70		info->total_nodes = total_nodes = num;
71		*flags |= 1 << c;
72		break;
73	case CLUSTER_OPT_LOCAL_NODE:
74		if (*flags & (1 << c)) {
75			xtables_error(PARAMETER_PROBLEM,
76				      "Can only specify "
77				      "`--cluster-local-node' once");
78		}
79		if (*flags & (1 << CLUSTER_OPT_NODE_MASK)) {
80			xtables_error(PARAMETER_PROBLEM, "You cannot use "
81				      "`--cluster-local-nodemask' and "
82				      "`--cluster-local-node'");
83		}
84		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
85
86		if (!xtables_strtoui(optarg, NULL, &num, 1,
87				     XT_CLUSTER_NODES_MAX)) {
88			xtables_error(PARAMETER_PROBLEM,
89				      "Unable to parse `%s' in "
90				      "`--cluster-local-node'", optarg);
91		}
92		if (invert)
93			info->flags |= (1 << XT_CLUSTER_F_INV);
94
95		info->node_mask = node_mask = (1 << (num - 1));
96		*flags |= 1 << c;
97		break;
98	case CLUSTER_OPT_NODE_MASK:
99		if (*flags & (1 << c)) {
100			xtables_error(PARAMETER_PROBLEM,
101				      "Can only specify "
102				      "`--cluster-local-node' once");
103		}
104		if (*flags & (1 << CLUSTER_OPT_LOCAL_NODE)) {
105			xtables_error(PARAMETER_PROBLEM, "You cannot use "
106				      "`--cluster-local-nodemask' and "
107				      "`--cluster-local-node'");
108		}
109		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
110
111		if (!xtables_strtoui(optarg, NULL, &num, 1,
112				     XT_CLUSTER_NODES_MAX)) {
113			xtables_error(PARAMETER_PROBLEM,
114				      "Unable to parse `%s' in "
115				      "`--cluster-local-node'", optarg);
116		}
117		if (invert)
118			info->flags |= (1 << XT_CLUSTER_F_INV);
119
120		info->node_mask = node_mask = num;
121		*flags |= 1 << c;
122		break;
123
124	case CLUSTER_OPT_HASH_SEED:
125		if (*flags & (1 << c)) {
126			xtables_error(PARAMETER_PROBLEM,
127				      "Can only specify "
128				      "`--cluster-hash-seed' once");
129		}
130		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) {
131			xtables_error(PARAMETER_PROBLEM,
132				      "Unable to parse `%s'", optarg);
133		}
134		info->hash_seed = num;
135		*flags |= 1 << c;
136		break;
137	}
138
139	return 1;
140}
141
142static void
143cluster_check(unsigned int flags)
144{
145	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
146		      (1 << CLUSTER_OPT_LOCAL_NODE) |
147		      (1 << CLUSTER_OPT_HASH_SEED)))
148		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
149		    (1 << CLUSTER_OPT_LOCAL_NODE) |
150		    (1 << CLUSTER_OPT_HASH_SEED))) {
151		if (node_mask >= (1ULL << total_nodes)) {
152			xtables_error(PARAMETER_PROBLEM,
153				      "cluster match: "
154				      "`--cluster-local-node' "
155				      "must be <= `--cluster-total-nodes'");
156		}
157		return;
158	}
159	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
160		      (1 << CLUSTER_OPT_NODE_MASK) |
161		      (1 << CLUSTER_OPT_HASH_SEED)))
162		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
163		    (1 << CLUSTER_OPT_NODE_MASK) |
164		    (1 << CLUSTER_OPT_HASH_SEED))) {
165		if (node_mask >= (1ULL << total_nodes)) {
166			xtables_error(PARAMETER_PROBLEM,
167				      "cluster match: "
168				      "`--cluster-local-nodemask' too big "
169				      "for `--cluster-total-nodes'");
170		}
171		return;
172	}
173	if (!(flags & (1 << CLUSTER_OPT_TOTAL_NODES))) {
174		xtables_error(PARAMETER_PROBLEM,
175			      "cluster match: `--cluster-total-nodes' "
176			      "is missing");
177	}
178	if (!(flags & (1 << CLUSTER_OPT_HASH_SEED))) {
179		xtables_error(PARAMETER_PROBLEM,
180			      "cluster match: `--cluster-hash-seed' "
181			      "is missing");
182	}
183	if (!(flags & ((1 << (CLUSTER_OPT_LOCAL_NODE) |
184		       (1 << (CLUSTER_OPT_NODE_MASK)))))) {
185		xtables_error(PARAMETER_PROBLEM,
186			      "cluster match: `--cluster-local-node' or"
187			      "`--cluster-local-nodemask' is missing");
188	}
189}
190
191static void
192cluster_print(const void *ip, const struct xt_entry_match *match, int numeric)
193{
194	const struct xt_cluster_match_info *info = (void *)match->data;
195
196	printf(" cluster ");
197	if (info->flags & XT_CLUSTER_F_INV)
198		printf("!node_mask=0x%08x", info->node_mask);
199	else
200		printf("node_mask=0x%08x", info->node_mask);
201
202	printf(" total_nodes=%u hash_seed=0x%08x",
203		info->total_nodes, info->hash_seed);
204}
205
206static void
207cluster_save(const void *ip, const struct xt_entry_match *match)
208{
209	const struct xt_cluster_match_info *info = (void *)match->data;
210
211	if (info->flags & XT_CLUSTER_F_INV)
212		printf(" ! --cluster-local-nodemask 0x%08x", info->node_mask);
213	else
214		printf(" --cluster-local-nodemask 0x%08x", info->node_mask);
215
216	printf(" --cluster-total-nodes %u --cluster-hash-seed 0x%08x",
217		info->total_nodes, info->hash_seed);
218}
219
220static struct xtables_match cluster_mt_reg = {
221	.family		= NFPROTO_UNSPEC,
222	.name		= "cluster",
223	.version	= XTABLES_VERSION,
224	.size		= XT_ALIGN(sizeof(struct xt_cluster_match_info)),
225	.userspacesize  = XT_ALIGN(sizeof(struct xt_cluster_match_info)),
226 	.help		= cluster_help,
227	.parse		= cluster_parse,
228	.final_check	= cluster_check,
229	.print		= cluster_print,
230	.save		= cluster_save,
231	.extra_opts	= cluster_opts,
232};
233
234void _init(void)
235{
236	xtables_register_match(&cluster_mt_reg);
237}
238