libxt_set.c revision d40f1628c3717daebc437a398a285e371b5b6f7f
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 <stdio.h>
13#include <netdb.h>
14#include <string.h>
15#include <stdlib.h>
16#include <getopt.h>
17#include <ctype.h>
18#include <errno.h>
19
20#include <xtables.h>
21#include <linux/netfilter/xt_set.h>
22#include "libxt_set.h"
23
24static void
25set_help(void)
26{
27	printf("set match options:\n"
28	       " [!] --match-set name flags\n"
29	       "		 'name' is the set name from to match,\n"
30	       "		 'flags' are the comma separated list of\n"
31	       "		 'src' and 'dst' specifications.\n");
32}
33
34static const struct option set_opts[] = {
35	{ .name = "match-set", .has_arg = true, .val = '1'},
36	{ .name = "set",       .has_arg = true, .val = '2'},
37	{ .name = NULL }
38};
39
40static void
41set_check(unsigned int flags)
42{
43	if (!flags)
44		xtables_error(PARAMETER_PROBLEM,
45			"You must specify `--match-set' with proper arguments");
46}
47
48static int
49set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
50	     const void *entry, struct xt_entry_match **match)
51{
52	struct xt_set_info_match_v0 *myinfo =
53		(struct xt_set_info_match_v0 *) (*match)->data;
54	struct xt_set_info_v0 *info = &myinfo->match_set;
55
56	switch (c) {
57	case '2':
58		fprintf(stderr,
59			"--set option deprecated, please use --match-set\n");
60	case '1':		/* --match-set <set> <flag>[,<flag> */
61		if (info->u.flags[0])
62			xtables_error(PARAMETER_PROBLEM,
63				      "--match-set can be specified only once");
64
65		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
66		if (invert)
67			info->u.flags[0] |= IPSET_MATCH_INV;
68
69		if (!argv[optind]
70		    || argv[optind][0] == '-'
71		    || argv[optind][0] == '!')
72			xtables_error(PARAMETER_PROBLEM,
73				      "--match-set requires two args.");
74
75		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
76			xtables_error(PARAMETER_PROBLEM,
77				      "setname `%s' too long, max %d characters.",
78				      optarg, IPSET_MAXNAMELEN - 1);
79
80		get_set_byname(optarg, (struct xt_set_info *)info);
81		parse_dirs_v0(argv[optind], info);
82		DEBUGP("parse: set index %u\n", info->index);
83		optind++;
84
85		*flags = 1;
86		break;
87
88	default:
89		return 0;
90	}
91
92	return 1;
93}
94
95static void
96print_match_v0(const char *prefix, const struct xt_set_info_v0 *info)
97{
98	int i;
99	char setname[IPSET_MAXNAMELEN];
100
101	get_set_byid(setname, info->index);
102	printf("%s%s %s",
103	       (info->u.flags[0] & IPSET_MATCH_INV) ? "! " : "",
104	       prefix,
105	       setname);
106	for (i = 0; i < IPSET_DIM_MAX; i++) {
107		if (!info->u.flags[i])
108			break;
109		printf("%s%s",
110		       i == 0 ? " " : ",",
111		       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
112	}
113	printf(" ");
114}
115
116/* Prints out the matchinfo. */
117static void
118set_print_v0(const void *ip, const struct xt_entry_match *match, int numeric)
119{
120	const struct xt_set_info_match_v0 *info = (const void *)match->data;
121
122	print_match_v0("match-set", &info->match_set);
123}
124
125static void
126set_save_v0(const void *ip, const struct xt_entry_match *match)
127{
128	const struct xt_set_info_match_v0 *info = (const void *)match->data;
129
130	print_match_v0("--match-set", &info->match_set);
131}
132
133static int
134set_parse(int c, char **argv, int invert, unsigned int *flags,
135	  const void *entry, struct xt_entry_match **match)
136{
137	struct xt_set_info_match *myinfo =
138		(struct xt_set_info_match *) (*match)->data;
139	struct xt_set_info *info = &myinfo->match_set;
140
141	switch (c) {
142	case '2':
143		fprintf(stderr,
144			"--set option deprecated, please use --match-set\n");
145	case '1':		/* --match-set <set> <flag>[,<flag> */
146		if (info->dim)
147			xtables_error(PARAMETER_PROBLEM,
148				      "--match-set can be specified only once");
149
150		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
151		if (invert)
152			info->flags |= IPSET_INV_MATCH;
153
154		if (!argv[optind]
155		    || argv[optind][0] == '-'
156		    || argv[optind][0] == '!')
157			xtables_error(PARAMETER_PROBLEM,
158				      "--match-set requires two args.");
159
160		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
161			xtables_error(PARAMETER_PROBLEM,
162				      "setname `%s' too long, max %d characters.",
163				      optarg, IPSET_MAXNAMELEN - 1);
164
165		get_set_byname(optarg, info);
166		parse_dirs(argv[optind], info);
167		DEBUGP("parse: set index %u\n", info->index);
168		optind++;
169
170		*flags = 1;
171		break;
172
173	default:
174		return 0;
175	}
176
177	return 1;
178}
179
180static void
181print_match(const char *prefix, const struct xt_set_info *info)
182{
183	int i;
184	char setname[IPSET_MAXNAMELEN];
185
186	get_set_byid(setname, info->index);
187	printf("%s%s %s",
188	       (info->flags & IPSET_INV_MATCH) ? "! " : "",
189	       prefix,
190	       setname);
191	for (i = 1; i <= info->dim; i++) {
192		printf("%s%s",
193		       i == 1 ? " " : ",",
194		       info->flags & (1 << i) ? "src" : "dst");
195	}
196	printf(" ");
197}
198
199/* Prints out the matchinfo. */
200static void
201set_print(const void *ip, const struct xt_entry_match *match, int numeric)
202{
203	const struct xt_set_info_match *info = (const void *)match->data;
204
205	print_match("match-set", &info->match_set);
206}
207
208static void
209set_save(const void *ip, const struct xt_entry_match *match)
210{
211	const struct xt_set_info_match *info = (const void *)match->data;
212
213	print_match("--match-set", &info->match_set);
214}
215
216static struct xtables_match set_mt_reg[] = {
217	{
218		.name		= "set",
219		.revision	= 0,
220		.version	= XTABLES_VERSION,
221		.family		= NFPROTO_IPV4,
222		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
223		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
224		.help		= set_help,
225		.parse		= set_parse_v0,
226		.final_check	= set_check,
227		.print		= set_print_v0,
228		.save		= set_save_v0,
229		.extra_opts	= set_opts,
230	},
231	{
232		.name		= "set",
233		.revision	= 1,
234		.version	= XTABLES_VERSION,
235		.family		= NFPROTO_UNSPEC,
236		.size		= XT_ALIGN(sizeof(struct xt_set_info_match)),
237		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match)),
238		.help		= set_help,
239		.parse		= set_parse,
240		.final_check	= set_check,
241		.print		= set_print,
242		.save		= set_save,
243		.extra_opts	= set_opts,
244	},
245};
246
247void _init(void)
248{
249	xtables_register_matches(set_mt_reg, ARRAY_SIZE(set_mt_reg));
250}
251