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 #define SET_TARGET_MAP 0x10
162 #define SET_TARGET_MAP_MARK 0x20
163 #define SET_TARGET_MAP_PRIO 0x40
164 #define SET_TARGET_MAP_QUEUE 0x80
165
166 static void
parse_target(char ** argv,int invert,struct xt_set_info * info,const char * what)167 parse_target(char **argv, int invert, struct xt_set_info *info,
168 const char *what)
169 {
170 if (info->dim)
171 xtables_error(PARAMETER_PROBLEM,
172 "--%s can be specified only once", what);
173 if (!argv[optind]
174 || argv[optind][0] == '-' || argv[optind][0] == '!')
175 xtables_error(PARAMETER_PROBLEM,
176 "--%s requires two args.", what);
177
178 if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
179 xtables_error(PARAMETER_PROBLEM,
180 "setname `%s' too long, max %d characters.",
181 optarg, IPSET_MAXNAMELEN - 1);
182
183 get_set_byname(optarg, info);
184 parse_dirs(argv[optind], info);
185 optind++;
186 }
187
188 static int
set_target_parse_v1(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)189 set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags,
190 const void *entry, struct xt_entry_target **target)
191 {
192 struct xt_set_info_target_v1 *myinfo =
193 (struct xt_set_info_target_v1 *) (*target)->data;
194
195 switch (c) {
196 case '1': /* --add-set <set> <flags> */
197 parse_target(argv, invert, &myinfo->add_set, "add-set");
198 *flags |= SET_TARGET_ADD;
199 break;
200 case '2': /* --del-set <set>[:<flags>] <flags> */
201 parse_target(argv, invert, &myinfo->del_set, "del-set");
202 *flags |= SET_TARGET_DEL;
203 break;
204 }
205 return 1;
206 }
207
208 static void
print_target(const char * prefix,const struct xt_set_info * info)209 print_target(const char *prefix, const struct xt_set_info *info)
210 {
211 int i;
212 char setname[IPSET_MAXNAMELEN];
213
214 if (info->index == IPSET_INVALID_ID)
215 return;
216 get_set_byid(setname, info->index);
217 printf(" %s %s", prefix, setname);
218 for (i = 1; i <= info->dim; i++) {
219 printf("%s%s",
220 i == 1 ? " " : ",",
221 info->flags & (1 << i) ? "src" : "dst");
222 }
223 }
224
225 static void
set_target_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)226 set_target_print_v1(const void *ip, const struct xt_entry_target *target,
227 int numeric)
228 {
229 const struct xt_set_info_target_v1 *info = (const void *)target->data;
230
231 print_target("add-set", &info->add_set);
232 print_target("del-set", &info->del_set);
233 }
234
235 static void
set_target_save_v1(const void * ip,const struct xt_entry_target * target)236 set_target_save_v1(const void *ip, const struct xt_entry_target *target)
237 {
238 const struct xt_set_info_target_v1 *info = (const void *)target->data;
239
240 print_target("--add-set", &info->add_set);
241 print_target("--del-set", &info->del_set);
242 }
243
244 /* Revision 2 */
245
246 static void
set_target_help_v2(void)247 set_target_help_v2(void)
248 {
249 printf("SET target options:\n"
250 " --add-set name flags [--exist] [--timeout n]\n"
251 " --del-set name flags\n"
252 " add/del src/dst IP/port from/to named sets,\n"
253 " where flags are the comma separated list of\n"
254 " 'src' and 'dst' specifications.\n");
255 }
256
257 static const struct option set_target_opts_v2[] = {
258 {.name = "add-set", .has_arg = true, .val = '1'},
259 {.name = "del-set", .has_arg = true, .val = '2'},
260 {.name = "exist", .has_arg = false, .val = '3'},
261 {.name = "timeout", .has_arg = true, .val = '4'},
262 XT_GETOPT_TABLEEND,
263 };
264
265 static void
set_target_check_v2(unsigned int flags)266 set_target_check_v2(unsigned int flags)
267 {
268 if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL)))
269 xtables_error(PARAMETER_PROBLEM,
270 "You must specify either `--add-set' or `--del-set'");
271 if (!(flags & SET_TARGET_ADD)) {
272 if (flags & SET_TARGET_EXIST)
273 xtables_error(PARAMETER_PROBLEM,
274 "Flag `--exist' can be used with `--add-set' only");
275 if (flags & SET_TARGET_TIMEOUT)
276 xtables_error(PARAMETER_PROBLEM,
277 "Option `--timeout' can be used with `--add-set' only");
278 }
279 }
280
281
282 static void
set_target_init_v2(struct xt_entry_target * target)283 set_target_init_v2(struct xt_entry_target *target)
284 {
285 struct xt_set_info_target_v2 *info =
286 (struct xt_set_info_target_v2 *) target->data;
287
288 info->add_set.index =
289 info->del_set.index = IPSET_INVALID_ID;
290 info->timeout = UINT32_MAX;
291 }
292
293 static int
set_target_parse_v2(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)294 set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
295 const void *entry, struct xt_entry_target **target)
296 {
297 struct xt_set_info_target_v2 *myinfo =
298 (struct xt_set_info_target_v2 *) (*target)->data;
299 unsigned int timeout;
300
301 switch (c) {
302 case '1': /* --add-set <set> <flags> */
303 parse_target(argv, invert, &myinfo->add_set, "add-set");
304 *flags |= SET_TARGET_ADD;
305 break;
306 case '2': /* --del-set <set>[:<flags>] <flags> */
307 parse_target(argv, invert, &myinfo->del_set, "del-set");
308 *flags |= SET_TARGET_DEL;
309 break;
310 case '3':
311 myinfo->flags |= IPSET_FLAG_EXIST;
312 *flags |= SET_TARGET_EXIST;
313 break;
314 case '4':
315 if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
316 xtables_error(PARAMETER_PROBLEM,
317 "Invalid value for option --timeout "
318 "or out of range 0-%u", UINT32_MAX - 1);
319 myinfo->timeout = timeout;
320 *flags |= SET_TARGET_TIMEOUT;
321 break;
322 }
323 return 1;
324 }
325
326 static void
set_target_print_v2(const void * ip,const struct xt_entry_target * target,int numeric)327 set_target_print_v2(const void *ip, const struct xt_entry_target *target,
328 int numeric)
329 {
330 const struct xt_set_info_target_v2 *info = (const void *)target->data;
331
332 print_target("add-set", &info->add_set);
333 if (info->flags & IPSET_FLAG_EXIST)
334 printf(" exist");
335 if (info->timeout != UINT32_MAX)
336 printf(" timeout %u", info->timeout);
337 print_target("del-set", &info->del_set);
338 }
339
340 static void
set_target_save_v2(const void * ip,const struct xt_entry_target * target)341 set_target_save_v2(const void *ip, const struct xt_entry_target *target)
342 {
343 const struct xt_set_info_target_v2 *info = (const void *)target->data;
344
345 print_target("--add-set", &info->add_set);
346 if (info->flags & IPSET_FLAG_EXIST)
347 printf(" --exist");
348 if (info->timeout != UINT32_MAX)
349 printf(" --timeout %u", info->timeout);
350 print_target("--del-set", &info->del_set);
351 }
352
353
354 /* Revision 3 */
355
356 static void
set_target_help_v3(void)357 set_target_help_v3(void)
358 {
359 printf("SET target options:\n"
360 " --add-set name flags [--exist] [--timeout n]\n"
361 " --del-set name flags\n"
362 " --map-set name flags"
363 " [--map-mark] [--map-prio] [--map-queue]\n"
364 " add/del src/dst IP/port from/to named sets,\n"
365 " where flags are the comma separated list of\n"
366 " 'src' and 'dst' specifications.\n");
367 }
368
369 static const struct option set_target_opts_v3[] = {
370 {.name = "add-set", .has_arg = true, .val = '1'},
371 {.name = "del-set", .has_arg = true, .val = '2'},
372 {.name = "exist", .has_arg = false, .val = '3'},
373 {.name = "timeout", .has_arg = true, .val = '4'},
374 {.name = "map-set", .has_arg = true, .val = '5'},
375 {.name = "map-mark", .has_arg = false, .val = '6'},
376 {.name = "map-prio", .has_arg = false, .val = '7'},
377 {.name = "map-queue", .has_arg = false, .val = '8'},
378 XT_GETOPT_TABLEEND,
379 };
380
381 static void
set_target_check_v3(unsigned int flags)382 set_target_check_v3(unsigned int flags)
383 {
384 if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL|SET_TARGET_MAP)))
385 xtables_error(PARAMETER_PROBLEM,
386 "You must specify either `--add-set' or "
387 "`--del-set' or `--map-set'");
388 if (!(flags & SET_TARGET_ADD)) {
389 if (flags & SET_TARGET_EXIST)
390 xtables_error(PARAMETER_PROBLEM,
391 "Flag `--exist' can be used with `--add-set' only");
392 if (flags & SET_TARGET_TIMEOUT)
393 xtables_error(PARAMETER_PROBLEM,
394 "Option `--timeout' can be used with `--add-set' only");
395 }
396 if (!(flags & SET_TARGET_MAP)) {
397 if (flags & SET_TARGET_MAP_MARK)
398 xtables_error(PARAMETER_PROBLEM,
399 "Flag `--map-mark' can be used with `--map-set' only");
400 if (flags & SET_TARGET_MAP_PRIO)
401 xtables_error(PARAMETER_PROBLEM,
402 "Flag `--map-prio' can be used with `--map-set' only");
403 if (flags & SET_TARGET_MAP_QUEUE)
404 xtables_error(PARAMETER_PROBLEM,
405 "Flag `--map-queue' can be used with `--map-set' only");
406 }
407 if ((flags & SET_TARGET_MAP) && !(flags & (SET_TARGET_MAP_MARK |
408 SET_TARGET_MAP_PRIO |
409 SET_TARGET_MAP_QUEUE)))
410 xtables_error(PARAMETER_PROBLEM,
411 "You must specify flags `--map-mark' or "
412 "'--map-prio` or `--map-queue'");
413 }
414
415 static void
set_target_init_v3(struct xt_entry_target * target)416 set_target_init_v3(struct xt_entry_target *target)
417 {
418 struct xt_set_info_target_v3 *info =
419 (struct xt_set_info_target_v3 *) target->data;
420
421 info->add_set.index =
422 info->del_set.index =
423 info->map_set.index = IPSET_INVALID_ID;
424 info->timeout = UINT32_MAX;
425 }
426
427 static int
set_target_parse_v3(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)428 set_target_parse_v3(int c, char **argv, int invert, unsigned int *flags,
429 const void *entry, struct xt_entry_target **target)
430 {
431 struct xt_set_info_target_v3 *myinfo =
432 (struct xt_set_info_target_v3 *) (*target)->data;
433 unsigned int timeout;
434
435 switch (c) {
436 case '1': /* --add-set <set> <flags> */
437 parse_target(argv, invert, &myinfo->add_set, "add-set");
438 *flags |= SET_TARGET_ADD;
439 break;
440 case '2': /* --del-set <set>[:<flags>] <flags> */
441 parse_target(argv, invert, &myinfo->del_set, "del-set");
442 *flags |= SET_TARGET_DEL;
443 break;
444 case '3':
445 myinfo->flags |= IPSET_FLAG_EXIST;
446 *flags |= SET_TARGET_EXIST;
447 break;
448 case '4':
449 if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
450 xtables_error(PARAMETER_PROBLEM,
451 "Invalid value for option --timeout "
452 "or out of range 0-%u", UINT32_MAX - 1);
453 myinfo->timeout = timeout;
454 *flags |= SET_TARGET_TIMEOUT;
455 break;
456 case '5': /* --map-set <set> <flags> */
457 parse_target(argv, invert, &myinfo->map_set, "map-set");
458 *flags |= SET_TARGET_MAP;
459 break;
460 case '6':
461 myinfo->flags |= IPSET_FLAG_MAP_SKBMARK;
462 *flags |= SET_TARGET_MAP_MARK;
463 break;
464 case '7':
465 myinfo->flags |= IPSET_FLAG_MAP_SKBPRIO;
466 *flags |= SET_TARGET_MAP_PRIO;
467 break;
468 case '8':
469 myinfo->flags |= IPSET_FLAG_MAP_SKBQUEUE;
470 *flags |= SET_TARGET_MAP_QUEUE;
471 break;
472 }
473 return 1;
474 }
475
476 static void
set_target_print_v3(const void * ip,const struct xt_entry_target * target,int numeric)477 set_target_print_v3(const void *ip, const struct xt_entry_target *target,
478 int numeric)
479 {
480 const struct xt_set_info_target_v3 *info = (const void *)target->data;
481
482 print_target("add-set", &info->add_set);
483 if (info->flags & IPSET_FLAG_EXIST)
484 printf(" exist");
485 if (info->timeout != UINT32_MAX)
486 printf(" timeout %u", info->timeout);
487 print_target("del-set", &info->del_set);
488 print_target("map-set", &info->map_set);
489 if (info->flags & IPSET_FLAG_MAP_SKBMARK)
490 printf(" map-mark");
491 if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
492 printf(" map-prio");
493 if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
494 printf(" map-queue");
495 }
496
497 static void
set_target_save_v3(const void * ip,const struct xt_entry_target * target)498 set_target_save_v3(const void *ip, const struct xt_entry_target *target)
499 {
500 const struct xt_set_info_target_v3 *info = (const void *)target->data;
501
502 print_target("--add-set", &info->add_set);
503 if (info->flags & IPSET_FLAG_EXIST)
504 printf(" --exist");
505 if (info->timeout != UINT32_MAX)
506 printf(" --timeout %u", info->timeout);
507 print_target("--del-set", &info->del_set);
508 print_target("--map-set", &info->map_set);
509 if (info->flags & IPSET_FLAG_MAP_SKBMARK)
510 printf(" --map-mark");
511 if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
512 printf(" --map-prio");
513 if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
514 printf(" --map-queue");
515 }
516
517 static struct xtables_target set_tg_reg[] = {
518 {
519 .name = "SET",
520 .revision = 0,
521 .version = XTABLES_VERSION,
522 .family = NFPROTO_IPV4,
523 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
524 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
525 .help = set_target_help_v0,
526 .init = set_target_init_v0,
527 .parse = set_target_parse_v0,
528 .final_check = set_target_check_v0,
529 .print = set_target_print_v0,
530 .save = set_target_save_v0,
531 .extra_opts = set_target_opts_v0,
532 },
533 {
534 .name = "SET",
535 .revision = 1,
536 .version = XTABLES_VERSION,
537 .family = NFPROTO_UNSPEC,
538 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
539 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
540 .help = set_target_help_v0,
541 .init = set_target_init_v1,
542 .parse = set_target_parse_v1,
543 .final_check = set_target_check_v0,
544 .print = set_target_print_v1,
545 .save = set_target_save_v1,
546 .extra_opts = set_target_opts_v0,
547 },
548 {
549 .name = "SET",
550 .revision = 2,
551 .version = XTABLES_VERSION,
552 .family = NFPROTO_UNSPEC,
553 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
554 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
555 .help = set_target_help_v2,
556 .init = set_target_init_v2,
557 .parse = set_target_parse_v2,
558 .final_check = set_target_check_v2,
559 .print = set_target_print_v2,
560 .save = set_target_save_v2,
561 .extra_opts = set_target_opts_v2,
562 },
563 {
564 .name = "SET",
565 .revision = 3,
566 .version = XTABLES_VERSION,
567 .family = NFPROTO_UNSPEC,
568 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
569 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
570 .help = set_target_help_v3,
571 .init = set_target_init_v3,
572 .parse = set_target_parse_v3,
573 .final_check = set_target_check_v3,
574 .print = set_target_print_v3,
575 .save = set_target_save_v3,
576 .extra_opts = set_target_opts_v3,
577 },
578 };
579
_init(void)580 void _init(void)
581 {
582 xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg));
583 }
584