libxt_cluster.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
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	default:
138		return 0;
139	}
140
141	return 1;
142}
143
144static void
145cluster_check(unsigned int flags)
146{
147	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
148		      (1 << CLUSTER_OPT_LOCAL_NODE) |
149		      (1 << CLUSTER_OPT_HASH_SEED)))
150		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
151		    (1 << CLUSTER_OPT_LOCAL_NODE) |
152		    (1 << CLUSTER_OPT_HASH_SEED))) {
153		if (node_mask >= (1ULL << total_nodes)) {
154			xtables_error(PARAMETER_PROBLEM,
155				      "cluster match: "
156				      "`--cluster-local-node' "
157				      "must be <= `--cluster-total-nodes'");
158		}
159		return;
160	}
161	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
162		      (1 << CLUSTER_OPT_NODE_MASK) |
163		      (1 << CLUSTER_OPT_HASH_SEED)))
164		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
165		    (1 << CLUSTER_OPT_NODE_MASK) |
166		    (1 << CLUSTER_OPT_HASH_SEED))) {
167		if (node_mask >= (1ULL << total_nodes)) {
168			xtables_error(PARAMETER_PROBLEM,
169				      "cluster match: "
170				      "`--cluster-local-nodemask' too big "
171				      "for `--cluster-total-nodes'");
172		}
173		return;
174	}
175	if (!(flags & (1 << CLUSTER_OPT_TOTAL_NODES))) {
176		xtables_error(PARAMETER_PROBLEM,
177			      "cluster match: `--cluster-total-nodes' "
178			      "is missing");
179	}
180	if (!(flags & (1 << CLUSTER_OPT_HASH_SEED))) {
181		xtables_error(PARAMETER_PROBLEM,
182			      "cluster match: `--cluster-hash-seed' "
183			      "is missing");
184	}
185	if (!(flags & ((1 << (CLUSTER_OPT_LOCAL_NODE) |
186		       (1 << (CLUSTER_OPT_NODE_MASK)))))) {
187		xtables_error(PARAMETER_PROBLEM,
188			      "cluster match: `--cluster-local-node' or"
189			      "`--cluster-local-nodemask' is missing");
190	}
191}
192
193static void
194cluster_print(const void *ip, const struct xt_entry_match *match, int numeric)
195{
196	const struct xt_cluster_match_info *info = (void *)match->data;
197
198	printf("cluster ");
199	if (info->flags & XT_CLUSTER_F_INV)
200		printf("!node_mask=0x%08x ", info->node_mask);
201	else
202		printf("node_mask=0x%08x ", info->node_mask);
203
204	printf("total_nodes=%u hash_seed=0x%08x ",
205		info->total_nodes, info->hash_seed);
206}
207
208static void
209cluster_save(const void *ip, const struct xt_entry_match *match)
210{
211	const struct xt_cluster_match_info *info = (void *)match->data;
212
213	if (info->flags & XT_CLUSTER_F_INV)
214		printf("! --cluster-local-nodemask 0x%08x ", info->node_mask);
215	else
216		printf("--cluster-local-nodemask 0x%08x ", info->node_mask);
217
218	printf("--cluster-total-nodes %u --cluster-hash-seed 0x%08x ",
219		info->total_nodes, info->hash_seed);
220}
221
222static struct xtables_match cluster_mt_reg = {
223	.family		= NFPROTO_UNSPEC,
224	.name		= "cluster",
225	.version	= XTABLES_VERSION,
226	.size		= XT_ALIGN(sizeof(struct xt_cluster_match_info)),
227	.userspacesize  = XT_ALIGN(sizeof(struct xt_cluster_match_info)),
228 	.help		= cluster_help,
229	.parse		= cluster_parse,
230	.final_check	= cluster_check,
231	.print		= cluster_print,
232	.save		= cluster_save,
233	.extra_opts	= cluster_opts,
234};
235
236void _init(void)
237{
238	xtables_register_match(&cluster_mt_reg);
239}
240