libxt_set.c revision d637ead63658d741501974c381889b3857073308
1/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 *                         Patrick Schaaf <bof@bof.de>
3 *                         Martin Josefsson <gandalf@wlug.westbo.se>
4 * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11/* Shared library add-on to iptables to add IP set matching. */
12#include <stdbool.h>
13#include <stdio.h>
14#include <netdb.h>
15#include <string.h>
16#include <stdlib.h>
17#include <getopt.h>
18#include <ctype.h>
19#include <errno.h>
20
21#include <xtables.h>
22#include <linux/netfilter/xt_set.h>
23#include "libxt_set.h"
24
25/* Revision 0 */
26
27static void
28set_help_v0(void)
29{
30	printf("set match options:\n"
31	       " [!] --match-set name flags\n"
32	       "		 'name' is the set name from to match,\n"
33	       "		 'flags' are the comma separated list of\n"
34	       "		 'src' and 'dst' specifications.\n");
35}
36
37static const struct option set_opts_v0[] = {
38	{.name = "match-set", .has_arg = true, .val = '1'},
39	{.name = "set",       .has_arg = true, .val = '2'},
40	XT_GETOPT_TABLEEND,
41};
42
43static void
44set_check_v0(unsigned int flags)
45{
46	if (!flags)
47		xtables_error(PARAMETER_PROBLEM,
48			"You must specify `--match-set' with proper arguments");
49}
50
51static int
52set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
53	     const void *entry, struct xt_entry_match **match)
54{
55	struct xt_set_info_match_v0 *myinfo =
56		(struct xt_set_info_match_v0 *) (*match)->data;
57	struct xt_set_info_v0 *info = &myinfo->match_set;
58
59	switch (c) {
60	case '2':
61		fprintf(stderr,
62			"--set option deprecated, please use --match-set\n");
63	case '1':		/* --match-set <set> <flag>[,<flag> */
64		if (info->u.flags[0])
65			xtables_error(PARAMETER_PROBLEM,
66				      "--match-set can be specified only once");
67		if (invert)
68			info->u.flags[0] |= IPSET_MATCH_INV;
69
70		if (!argv[optind]
71		    || argv[optind][0] == '-'
72		    || argv[optind][0] == '!')
73			xtables_error(PARAMETER_PROBLEM,
74				      "--match-set requires two args.");
75
76		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
77			xtables_error(PARAMETER_PROBLEM,
78				      "setname `%s' too long, max %d characters.",
79				      optarg, IPSET_MAXNAMELEN - 1);
80
81		get_set_byname(optarg, (struct xt_set_info *)info);
82		parse_dirs_v0(argv[optind], info);
83		DEBUGP("parse: set index %u\n", info->index);
84		optind++;
85
86		*flags = 1;
87		break;
88	}
89
90	return 1;
91}
92
93static void
94print_match_v0(const char *prefix, const struct xt_set_info_v0 *info)
95{
96	int i;
97	char setname[IPSET_MAXNAMELEN];
98
99	get_set_byid(setname, info->index);
100	printf("%s %s %s",
101	       (info->u.flags[0] & IPSET_MATCH_INV) ? " !" : "",
102	       prefix,
103	       setname);
104	for (i = 0; i < IPSET_DIM_MAX; i++) {
105		if (!info->u.flags[i])
106			break;
107		printf("%s%s",
108		       i == 0 ? " " : ",",
109		       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
110	}
111}
112
113/* Prints out the matchinfo. */
114static void
115set_print_v0(const void *ip, const struct xt_entry_match *match, int numeric)
116{
117	const struct xt_set_info_match_v0 *info = (const void *)match->data;
118
119	print_match_v0("match-set", &info->match_set);
120}
121
122static void
123set_save_v0(const void *ip, const struct xt_entry_match *match)
124{
125	const struct xt_set_info_match_v0 *info = (const void *)match->data;
126
127	print_match_v0("--match-set", &info->match_set);
128}
129
130/* Revision 1 */
131static int
132set_parse_v1(int c, char **argv, int invert, unsigned int *flags,
133	     const void *entry, struct xt_entry_match **match)
134{
135	struct xt_set_info_match_v1 *myinfo =
136		(struct xt_set_info_match_v1 *) (*match)->data;
137	struct xt_set_info *info = &myinfo->match_set;
138
139	switch (c) {
140	case '2':
141		fprintf(stderr,
142			"--set option deprecated, please use --match-set\n");
143	case '1':		/* --match-set <set> <flag>[,<flag> */
144		if (info->dim)
145			xtables_error(PARAMETER_PROBLEM,
146				      "--match-set can be specified only once");
147		if (invert)
148			info->flags |= IPSET_INV_MATCH;
149
150		if (!argv[optind]
151		    || argv[optind][0] == '-'
152		    || argv[optind][0] == '!')
153			xtables_error(PARAMETER_PROBLEM,
154				      "--match-set requires two args.");
155
156		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
157			xtables_error(PARAMETER_PROBLEM,
158				      "setname `%s' too long, max %d characters.",
159				      optarg, IPSET_MAXNAMELEN - 1);
160
161		get_set_byname(optarg, info);
162		parse_dirs(argv[optind], info);
163		DEBUGP("parse: set index %u\n", info->index);
164		optind++;
165
166		*flags = 1;
167		break;
168	}
169
170	return 1;
171}
172
173static void
174print_match(const char *prefix, const struct xt_set_info *info)
175{
176	int i;
177	char setname[IPSET_MAXNAMELEN];
178
179	get_set_byid(setname, info->index);
180	printf("%s %s %s",
181	       (info->flags & IPSET_INV_MATCH) ? " !" : "",
182	       prefix,
183	       setname);
184	for (i = 1; i <= info->dim; i++) {
185		printf("%s%s",
186		       i == 1 ? " " : ",",
187		       info->flags & (1 << i) ? "src" : "dst");
188	}
189}
190
191/* Prints out the matchinfo. */
192static void
193set_print_v1(const void *ip, const struct xt_entry_match *match, int numeric)
194{
195	const struct xt_set_info_match_v1 *info = (const void *)match->data;
196
197	print_match("match-set", &info->match_set);
198}
199
200static void
201set_save_v1(const void *ip, const struct xt_entry_match *match)
202{
203	const struct xt_set_info_match_v1 *info = (const void *)match->data;
204
205	print_match("--match-set", &info->match_set);
206}
207
208/* Revision 2 */
209static void
210set_help_v2(void)
211{
212	printf("set match options:\n"
213	       " [!] --match-set name flags [--return-nomatch]\n"
214	       "		 'name' is the set name from to match,\n"
215	       "		 'flags' are the comma separated list of\n"
216	       "		 'src' and 'dst' specifications.\n");
217}
218
219static const struct option set_opts_v2[] = {
220	{.name = "match-set",		.has_arg = true,	.val = '1'},
221	{.name = "set",			.has_arg = true,	.val = '2'},
222	{.name = "return-nomatch",	.has_arg = false,	.val = '3'},
223	XT_GETOPT_TABLEEND,
224};
225
226static int
227set_parse_v2(int c, char **argv, int invert, unsigned int *flags,
228	     const void *entry, struct xt_entry_match **match)
229{
230	struct xt_set_info_match_v1 *myinfo =
231		(struct xt_set_info_match_v1 *) (*match)->data;
232	struct xt_set_info *info = &myinfo->match_set;
233
234	switch (c) {
235	case '3':
236		info->flags |= IPSET_RETURN_NOMATCH;
237		break;
238	case '2':
239		fprintf(stderr,
240			"--set option deprecated, please use --match-set\n");
241	case '1':		/* --match-set <set> <flag>[,<flag> */
242		if (info->dim)
243			xtables_error(PARAMETER_PROBLEM,
244				      "--match-set can be specified only once");
245		if (invert)
246			info->flags |= IPSET_INV_MATCH;
247
248		if (!argv[optind]
249		    || argv[optind][0] == '-'
250		    || argv[optind][0] == '!')
251			xtables_error(PARAMETER_PROBLEM,
252				      "--match-set requires two args.");
253
254		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
255			xtables_error(PARAMETER_PROBLEM,
256				      "setname `%s' too long, max %d characters.",
257				      optarg, IPSET_MAXNAMELEN - 1);
258
259		get_set_byname(optarg, info);
260		parse_dirs(argv[optind], info);
261		DEBUGP("parse: set index %u\n", info->index);
262		optind++;
263
264		*flags = 1;
265		break;
266	}
267
268	return 1;
269}
270
271/* Prints out the matchinfo. */
272static void
273set_print_v2(const void *ip, const struct xt_entry_match *match, int numeric)
274{
275	const struct xt_set_info_match_v1 *info = (const void *)match->data;
276
277	print_match("match-set", &info->match_set);
278	if (info->match_set.flags & IPSET_RETURN_NOMATCH)
279		printf(" return-nomatch");
280}
281
282static void
283set_save_v2(const void *ip, const struct xt_entry_match *match)
284{
285	const struct xt_set_info_match_v1 *info = (const void *)match->data;
286
287	print_match("--match-set", &info->match_set);
288	if (info->match_set.flags & IPSET_RETURN_NOMATCH)
289		printf(" --return-nomatch");
290}
291
292static struct xtables_match set_mt_reg[] = {
293	{
294		.name		= "set",
295		.revision	= 0,
296		.version	= XTABLES_VERSION,
297		.family		= NFPROTO_IPV4,
298		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
299		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
300		.help		= set_help_v0,
301		.parse		= set_parse_v0,
302		.final_check	= set_check_v0,
303		.print		= set_print_v0,
304		.save		= set_save_v0,
305		.extra_opts	= set_opts_v0,
306	},
307	{
308		.name		= "set",
309		.revision	= 1,
310		.version	= XTABLES_VERSION,
311		.family		= NFPROTO_UNSPEC,
312		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
313		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
314		.help		= set_help_v0,
315		.parse		= set_parse_v1,
316		.final_check	= set_check_v0,
317		.print		= set_print_v1,
318		.save		= set_save_v1,
319		.extra_opts	= set_opts_v0,
320	},
321	{
322		.name		= "set",
323		.revision	= 2,
324		.version	= XTABLES_VERSION,
325		.family		= NFPROTO_UNSPEC,
326		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
327		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
328		.help		= set_help_v2,
329		.parse		= set_parse_v2,
330		.final_check	= set_check_v0,
331		.print		= set_print_v2,
332		.save		= set_save_v2,
333		.extra_opts	= set_opts_v2,
334	},
335};
336
337void _init(void)
338{
339	xtables_register_matches(set_mt_reg, ARRAY_SIZE(set_mt_reg));
340}
341