libxt_set.c revision d09b6d591ca7d7d7575cb6aa20384c9830f777ab
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
25static void
26set_help(void)
27{
28	printf("set match options:\n"
29	       " [!] --match-set name flags\n"
30	       "		 'name' is the set name from to match,\n"
31	       "		 'flags' are the comma separated list of\n"
32	       "		 'src' and 'dst' specifications.\n");
33}
34
35static const struct option set_opts[] = {
36	{.name = "match-set", .has_arg = true, .val = '1'},
37	{.name = "set",       .has_arg = true, .val = '2'},
38	XT_GETOPT_TABLEEND,
39};
40
41static void
42set_check(unsigned int flags)
43{
44	if (!flags)
45		xtables_error(PARAMETER_PROBLEM,
46			"You must specify `--match-set' with proper arguments");
47}
48
49static int
50set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
51	     const void *entry, struct xt_entry_match **match)
52{
53	struct xt_set_info_match_v0 *myinfo =
54		(struct xt_set_info_match_v0 *) (*match)->data;
55	struct xt_set_info_v0 *info = &myinfo->match_set;
56
57	switch (c) {
58	case '2':
59		fprintf(stderr,
60			"--set option deprecated, please use --match-set\n");
61	case '1':		/* --match-set <set> <flag>[,<flag> */
62		if (info->u.flags[0])
63			xtables_error(PARAMETER_PROBLEM,
64				      "--match-set can be specified only once");
65
66		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
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	printf(" ");
112}
113
114/* Prints out the matchinfo. */
115static void
116set_print_v0(const void *ip, const struct xt_entry_match *match, int numeric)
117{
118	const struct xt_set_info_match_v0 *info = (const void *)match->data;
119
120	print_match_v0("match-set", &info->match_set);
121}
122
123static void
124set_save_v0(const void *ip, const struct xt_entry_match *match)
125{
126	const struct xt_set_info_match_v0 *info = (const void *)match->data;
127
128	print_match_v0("--match-set", &info->match_set);
129}
130
131static int
132set_parse(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 *myinfo =
136		(struct xt_set_info_match *) (*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
148		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
149		if (invert)
150			info->flags |= IPSET_INV_MATCH;
151
152		if (!argv[optind]
153		    || argv[optind][0] == '-'
154		    || argv[optind][0] == '!')
155			xtables_error(PARAMETER_PROBLEM,
156				      "--match-set requires two args.");
157
158		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
159			xtables_error(PARAMETER_PROBLEM,
160				      "setname `%s' too long, max %d characters.",
161				      optarg, IPSET_MAXNAMELEN - 1);
162
163		get_set_byname(optarg, info);
164		parse_dirs(argv[optind], info);
165		DEBUGP("parse: set index %u\n", info->index);
166		optind++;
167
168		*flags = 1;
169		break;
170	}
171
172	return 1;
173}
174
175static void
176print_match(const char *prefix, const struct xt_set_info *info)
177{
178	int i;
179	char setname[IPSET_MAXNAMELEN];
180
181	get_set_byid(setname, info->index);
182	printf("%s%s %s",
183	       (info->flags & IPSET_INV_MATCH) ? "! " : "",
184	       prefix,
185	       setname);
186	for (i = 1; i <= info->dim; i++) {
187		printf("%s%s",
188		       i == 1 ? " " : ",",
189		       info->flags & (1 << i) ? "src" : "dst");
190	}
191	printf(" ");
192}
193
194/* Prints out the matchinfo. */
195static void
196set_print(const void *ip, const struct xt_entry_match *match, int numeric)
197{
198	const struct xt_set_info_match *info = (const void *)match->data;
199
200	print_match("match-set", &info->match_set);
201}
202
203static void
204set_save(const void *ip, const struct xt_entry_match *match)
205{
206	const struct xt_set_info_match *info = (const void *)match->data;
207
208	print_match("--match-set", &info->match_set);
209}
210
211static struct xtables_match set_mt_reg[] = {
212	{
213		.name		= "set",
214		.revision	= 0,
215		.version	= XTABLES_VERSION,
216		.family		= NFPROTO_IPV4,
217		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
218		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
219		.help		= set_help,
220		.parse		= set_parse_v0,
221		.final_check	= set_check,
222		.print		= set_print_v0,
223		.save		= set_save_v0,
224		.extra_opts	= set_opts,
225	},
226	{
227		.name		= "set",
228		.revision	= 1,
229		.version	= XTABLES_VERSION,
230		.family		= NFPROTO_UNSPEC,
231		.size		= XT_ALIGN(sizeof(struct xt_set_info_match)),
232		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match)),
233		.help		= set_help,
234		.parse		= set_parse,
235		.final_check	= set_check,
236		.print		= set_print,
237		.save		= set_save,
238		.extra_opts	= set_opts,
239	},
240};
241
242void _init(void)
243{
244	xtables_register_matches(set_mt_reg, ARRAY_SIZE(set_mt_reg));
245}
246