• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 mangling target. */
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 
20 #include <xtables.h>
21 #include <linux/netfilter/xt_set.h>
22 #include "libxt_set.h"
23 
24 /* Revision 0 */
25 
26 static void
set_target_help_v0(void)27 set_target_help_v0(void)
28 {
29 	printf("SET target options:\n"
30 	       " --add-set name flags\n"
31 	       " --del-set name flags\n"
32 	       "		add/del src/dst IP/port from/to named sets,\n"
33 	       "		where flags are the comma separated list of\n"
34 	       "		'src' and 'dst' specifications.\n");
35 }
36 
37 static const struct option set_target_opts_v0[] = {
38 	{.name = "add-set", .has_arg = true, .val = '1'},
39 	{.name = "del-set", .has_arg = true, .val = '2'},
40 	XT_GETOPT_TABLEEND,
41 };
42 
43 static void
set_target_check_v0(unsigned int flags)44 set_target_check_v0(unsigned int flags)
45 {
46 	if (!flags)
47 		xtables_error(PARAMETER_PROBLEM,
48 			   "You must specify either `--add-set' or `--del-set'");
49 }
50 
51 static void
set_target_init_v0(struct xt_entry_target * target)52 set_target_init_v0(struct xt_entry_target *target)
53 {
54 	struct xt_set_info_target_v0 *info =
55 		(struct xt_set_info_target_v0 *) target->data;
56 
57 	info->add_set.index =
58 	info->del_set.index = IPSET_INVALID_ID;
59 
60 }
61 
62 static void
parse_target_v0(char ** argv,int invert,unsigned int * flags,struct xt_set_info_v0 * info,const char * what)63 parse_target_v0(char **argv, int invert, unsigned int *flags,
64 		struct xt_set_info_v0 *info, const char *what)
65 {
66 	if (info->u.flags[0])
67 		xtables_error(PARAMETER_PROBLEM,
68 			      "--%s can be specified only once", what);
69 
70 	if (!argv[optind]
71 	    || argv[optind][0] == '-' || argv[optind][0] == '!')
72 		xtables_error(PARAMETER_PROBLEM,
73 			      "--%s requires two args.", what);
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 	optind++;
83 
84 	*flags = 1;
85 }
86 
87 static int
set_target_parse_v0(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)88 set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags,
89 		    const void *entry, struct xt_entry_target **target)
90 {
91 	struct xt_set_info_target_v0 *myinfo =
92 		(struct xt_set_info_target_v0 *) (*target)->data;
93 
94 	switch (c) {
95 	case '1':		/* --add-set <set> <flags> */
96 		parse_target_v0(argv, invert, flags,
97 				&myinfo->add_set, "add-set");
98 		break;
99 	case '2':		/* --del-set <set>[:<flags>] <flags> */
100 		parse_target_v0(argv, invert, flags,
101 				&myinfo->del_set, "del-set");
102 		break;
103 	}
104 	return 1;
105 }
106 
107 static void
print_target_v0(const char * prefix,const struct xt_set_info_v0 * info)108 print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
109 {
110 	int i;
111 	char setname[IPSET_MAXNAMELEN];
112 
113 	if (info->index == IPSET_INVALID_ID)
114 		return;
115 	get_set_byid(setname, info->index);
116 	printf(" %s %s", prefix, setname);
117 	for (i = 0; i < IPSET_DIM_MAX; i++) {
118 		if (!info->u.flags[i])
119 			break;
120 		printf("%s%s",
121 		       i == 0 ? " " : ",",
122 		       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
123 	}
124 }
125 
126 static void
set_target_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)127 set_target_print_v0(const void *ip, const struct xt_entry_target *target,
128                     int numeric)
129 {
130 	const struct xt_set_info_target_v0 *info = (const void *)target->data;
131 
132 	print_target_v0("add-set", &info->add_set);
133 	print_target_v0("del-set", &info->del_set);
134 }
135 
136 static void
set_target_save_v0(const void * ip,const struct xt_entry_target * target)137 set_target_save_v0(const void *ip, const struct xt_entry_target *target)
138 {
139 	const struct xt_set_info_target_v0 *info = (const void *)target->data;
140 
141 	print_target_v0("--add-set", &info->add_set);
142 	print_target_v0("--del-set", &info->del_set);
143 }
144 
145 /* Revision 1 */
146 static void
set_target_init_v1(struct xt_entry_target * target)147 set_target_init_v1(struct xt_entry_target *target)
148 {
149 	struct xt_set_info_target_v1 *info =
150 		(struct xt_set_info_target_v1 *) target->data;
151 
152 	info->add_set.index =
153 	info->del_set.index = IPSET_INVALID_ID;
154 
155 }
156 
157 #define SET_TARGET_ADD		0x1
158 #define SET_TARGET_DEL		0x2
159 #define SET_TARGET_EXIST	0x4
160 #define SET_TARGET_TIMEOUT	0x8
161 
162 static void
parse_target(char ** argv,int invert,struct xt_set_info * info,const char * what)163 parse_target(char **argv, int invert, struct xt_set_info *info,
164 	     const char *what)
165 {
166 	if (info->dim)
167 		xtables_error(PARAMETER_PROBLEM,
168 			      "--%s can be specified only once", what);
169 	if (!argv[optind]
170 	    || argv[optind][0] == '-' || argv[optind][0] == '!')
171 		xtables_error(PARAMETER_PROBLEM,
172 			      "--%s requires two args.", what);
173 
174 	if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
175 		xtables_error(PARAMETER_PROBLEM,
176 			      "setname `%s' too long, max %d characters.",
177 			      optarg, IPSET_MAXNAMELEN - 1);
178 
179 	get_set_byname(optarg, info);
180 	parse_dirs(argv[optind], info);
181 	optind++;
182 }
183 
184 static int
set_target_parse_v1(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)185 set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags,
186 		    const void *entry, struct xt_entry_target **target)
187 {
188 	struct xt_set_info_target_v1 *myinfo =
189 		(struct xt_set_info_target_v1 *) (*target)->data;
190 
191 	switch (c) {
192 	case '1':		/* --add-set <set> <flags> */
193 		parse_target(argv, invert, &myinfo->add_set, "add-set");
194 		*flags |= SET_TARGET_ADD;
195 		break;
196 	case '2':		/* --del-set <set>[:<flags>] <flags> */
197 		parse_target(argv, invert, &myinfo->del_set, "del-set");
198 		*flags |= SET_TARGET_DEL;
199 		break;
200 	}
201 	return 1;
202 }
203 
204 static void
print_target(const char * prefix,const struct xt_set_info * info)205 print_target(const char *prefix, const struct xt_set_info *info)
206 {
207 	int i;
208 	char setname[IPSET_MAXNAMELEN];
209 
210 	if (info->index == IPSET_INVALID_ID)
211 		return;
212 	get_set_byid(setname, info->index);
213 	printf(" %s %s", prefix, setname);
214 	for (i = 1; i <= info->dim; i++) {
215 		printf("%s%s",
216 		       i == 1 ? " " : ",",
217 		       info->flags & (1 << i) ? "src" : "dst");
218 	}
219 }
220 
221 static void
set_target_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)222 set_target_print_v1(const void *ip, const struct xt_entry_target *target,
223 		    int numeric)
224 {
225 	const struct xt_set_info_target_v1 *info = (const void *)target->data;
226 
227 	print_target("add-set", &info->add_set);
228 	print_target("del-set", &info->del_set);
229 }
230 
231 static void
set_target_save_v1(const void * ip,const struct xt_entry_target * target)232 set_target_save_v1(const void *ip, const struct xt_entry_target *target)
233 {
234 	const struct xt_set_info_target_v1 *info = (const void *)target->data;
235 
236 	print_target("--add-set", &info->add_set);
237 	print_target("--del-set", &info->del_set);
238 }
239 
240 /* Revision 2 */
241 
242 static void
set_target_help_v2(void)243 set_target_help_v2(void)
244 {
245 	printf("SET target options:\n"
246 	       " --add-set name flags [--exist] [--timeout n]\n"
247 	       " --del-set name flags\n"
248 	       "		add/del src/dst IP/port from/to named sets,\n"
249 	       "		where flags are the comma separated list of\n"
250 	       "		'src' and 'dst' specifications.\n");
251 }
252 
253 static const struct option set_target_opts_v2[] = {
254 	{.name = "add-set", .has_arg = true,  .val = '1'},
255 	{.name = "del-set", .has_arg = true,  .val = '2'},
256 	{.name = "exist",   .has_arg = false, .val = '3'},
257 	{.name = "timeout", .has_arg = true,  .val = '4'},
258 	XT_GETOPT_TABLEEND,
259 };
260 
261 static void
set_target_check_v2(unsigned int flags)262 set_target_check_v2(unsigned int flags)
263 {
264 	if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL)))
265 		xtables_error(PARAMETER_PROBLEM,
266 			   "You must specify either `--add-set' or `--del-set'");
267 	if (!(flags & SET_TARGET_ADD)) {
268 		if (flags & SET_TARGET_EXIST)
269 			xtables_error(PARAMETER_PROBLEM,
270 				"Flag `--exist' can be used with `--add-set' only");
271 		if (flags & SET_TARGET_TIMEOUT)
272 			xtables_error(PARAMETER_PROBLEM,
273 				"Option `--timeout' can be used with `--add-set' only");
274 	}
275 }
276 
277 
278 static void
set_target_init_v2(struct xt_entry_target * target)279 set_target_init_v2(struct xt_entry_target *target)
280 {
281 	struct xt_set_info_target_v2 *info =
282 		(struct xt_set_info_target_v2 *) target->data;
283 
284 	info->add_set.index =
285 	info->del_set.index = IPSET_INVALID_ID;
286 	info->timeout = UINT32_MAX;
287 }
288 
289 static int
set_target_parse_v2(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)290 set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
291 		    const void *entry, struct xt_entry_target **target)
292 {
293 	struct xt_set_info_target_v2 *myinfo =
294 		(struct xt_set_info_target_v2 *) (*target)->data;
295 	unsigned int timeout;
296 
297 	switch (c) {
298 	case '1':		/* --add-set <set> <flags> */
299 		parse_target(argv, invert, &myinfo->add_set, "add-set");
300 		*flags |= SET_TARGET_ADD;
301 		break;
302 	case '2':		/* --del-set <set>[:<flags>] <flags> */
303 		parse_target(argv, invert, &myinfo->del_set, "del-set");
304 		*flags |= SET_TARGET_DEL;
305 		break;
306 	case '3':
307 		myinfo->flags |= IPSET_FLAG_EXIST;
308 		*flags |= SET_TARGET_EXIST;
309 		break;
310 	case '4':
311 		if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
312 			xtables_error(PARAMETER_PROBLEM,
313 				      "Invalid value for option --timeout "
314 				      "or out of range 0-%u", UINT32_MAX - 1);
315 		myinfo->timeout = timeout;
316 		*flags |= SET_TARGET_TIMEOUT;
317 		break;
318 	}
319 	return 1;
320 }
321 
322 static void
set_target_print_v2(const void * ip,const struct xt_entry_target * target,int numeric)323 set_target_print_v2(const void *ip, const struct xt_entry_target *target,
324 		    int numeric)
325 {
326 	const struct xt_set_info_target_v2 *info = (const void *)target->data;
327 
328 	print_target("add-set", &info->add_set);
329 	if (info->flags & IPSET_FLAG_EXIST)
330 		printf(" exist");
331 	if (info->timeout != UINT32_MAX)
332 		printf(" timeout %u", info->timeout);
333 	print_target("del-set", &info->del_set);
334 }
335 
336 static void
set_target_save_v2(const void * ip,const struct xt_entry_target * target)337 set_target_save_v2(const void *ip, const struct xt_entry_target *target)
338 {
339 	const struct xt_set_info_target_v2 *info = (const void *)target->data;
340 
341 	print_target("--add-set", &info->add_set);
342 	if (info->flags & IPSET_FLAG_EXIST)
343 		printf(" --exist");
344 	if (info->timeout != UINT32_MAX)
345 		printf(" --timeout %u", info->timeout);
346 	print_target("--del-set", &info->del_set);
347 }
348 
349 static struct xtables_target set_tg_reg[] = {
350 	{
351 		.name		= "SET",
352 		.revision	= 0,
353 		.version	= XTABLES_VERSION,
354 		.family		= NFPROTO_IPV4,
355 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
356 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
357 		.help		= set_target_help_v0,
358 		.init		= set_target_init_v0,
359 		.parse		= set_target_parse_v0,
360 		.final_check	= set_target_check_v0,
361 		.print		= set_target_print_v0,
362 		.save		= set_target_save_v0,
363 		.extra_opts	= set_target_opts_v0,
364 	},
365 	{
366 		.name		= "SET",
367 		.revision	= 1,
368 		.version	= XTABLES_VERSION,
369 		.family		= NFPROTO_UNSPEC,
370 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
371 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
372 		.help		= set_target_help_v0,
373 		.init		= set_target_init_v1,
374 		.parse		= set_target_parse_v1,
375 		.final_check	= set_target_check_v0,
376 		.print		= set_target_print_v1,
377 		.save		= set_target_save_v1,
378 		.extra_opts	= set_target_opts_v0,
379 	},
380 	{
381 		.name		= "SET",
382 		.revision	= 2,
383 		.version	= XTABLES_VERSION,
384 		.family		= NFPROTO_UNSPEC,
385 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
386 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
387 		.help		= set_target_help_v2,
388 		.init		= set_target_init_v2,
389 		.parse		= set_target_parse_v2,
390 		.final_check	= set_target_check_v2,
391 		.print		= set_target_print_v2,
392 		.save		= set_target_save_v2,
393 		.extra_opts	= set_target_opts_v2,
394 	},
395 };
396 
_init(void)397 void _init(void)
398 {
399 	xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg));
400 }
401