summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libxt_SET.c207
-rw-r--r--extensions/libxt_SET.man8
-rw-r--r--extensions/libxt_set.c52
-rw-r--r--include/linux/netfilter/xt_set.h20
4 files changed, 227 insertions, 60 deletions
diff --git a/extensions/libxt_SET.c b/extensions/libxt_SET.c
index 2f915bcd..51c0cec6 100644
--- a/extensions/libxt_SET.c
+++ b/extensions/libxt_SET.c
@@ -21,8 +21,10 @@
#include <linux/netfilter/xt_set.h>
#include "libxt_set.h"
+/* Revision 0 */
+
static void
-set_target_help(void)
+set_target_help_v0(void)
{
printf("SET target options:\n"
" --add-set name flags\n"
@@ -32,14 +34,14 @@ set_target_help(void)
" 'src' and 'dst' specifications.\n");
}
-static const struct option set_target_opts[] = {
+static const struct option set_target_opts_v0[] = {
{.name = "add-set", .has_arg = true, .val = '1'},
{.name = "del-set", .has_arg = true, .val = '2'},
XT_GETOPT_TABLEEND,
};
static void
-set_target_check(unsigned int flags)
+set_target_check_v0(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
@@ -144,20 +146,29 @@ set_target_save_v0(const void *ip, const struct xt_entry_target *target)
print_target_v0("--del-set", &info->del_set);
}
+/* Revision 1 */
+
+#define set_target_help_v1 set_target_help_v0
+
static void
-set_target_init(struct xt_entry_target *target)
+set_target_init_v1(struct xt_entry_target *target)
{
- struct xt_set_info_target *info =
- (struct xt_set_info_target *) target->data;
+ struct xt_set_info_target_v1 *info =
+ (struct xt_set_info_target_v1 *) target->data;
info->add_set.index =
info->del_set.index = IPSET_INVALID_ID;
}
+#define SET_TARGET_ADD 0x1
+#define SET_TARGET_DEL 0x2
+#define SET_TARGET_EXIST 0x4
+#define SET_TARGET_TIMEOUT 0x8
+
static void
-parse_target(char **argv, int invert, unsigned int *flags,
- struct xt_set_info *info, const char *what)
+parse_target(char **argv, int invert, struct xt_set_info *info,
+ const char *what)
{
if (info->dim)
xtables_error(PARAMETER_PROBLEM,
@@ -180,30 +191,30 @@ parse_target(char **argv, int invert, unsigned int *flags,
get_set_byname(optarg, info);
parse_dirs(argv[optind], info);
optind++;
-
- *flags = 1;
}
static int
-set_target_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
{
- struct xt_set_info_target *myinfo =
- (struct xt_set_info_target *) (*target)->data;
+ struct xt_set_info_target_v1 *myinfo =
+ (struct xt_set_info_target_v1 *) (*target)->data;
switch (c) {
case '1': /* --add-set <set> <flags> */
- parse_target(argv, invert, flags,
- &myinfo->add_set, "add-set");
+ parse_target(argv, invert, &myinfo->add_set, "add-set");
+ *flags |= SET_TARGET_ADD;
break;
case '2': /* --del-set <set>[:<flags>] <flags> */
- parse_target(argv, invert, flags,
- &myinfo->del_set, "del-set");
+ parse_target(argv, invert, &myinfo->del_set, "del-set");
+ *flags |= SET_TARGET_DEL;
break;
}
return 1;
}
+#define set_target_check_v1 set_target_check_v0
+
static void
print_target(const char *prefix, const struct xt_set_info *info)
{
@@ -222,21 +233,132 @@ print_target(const char *prefix, const struct xt_set_info *info)
}
static void
-set_target_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
+set_target_print_v1(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_set_info_target_v1 *info = (const void *)target->data;
+
+ print_target("add-set", &info->add_set);
+ print_target("del-set", &info->del_set);
+}
+
+static void
+set_target_save_v1(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_set_info_target_v1 *info = (const void *)target->data;
+
+ print_target("--add-set", &info->add_set);
+ print_target("--del-set", &info->del_set);
+}
+
+#define set_target_opts_v1 set_target_opts_v0
+
+/* Revision 2 */
+
+static void
+set_target_help_v2(void)
+{
+ printf("SET target options:\n"
+ " --add-set name flags [--exist] [--timeout n]\n"
+ " --del-set name flags\n"
+ " add/del src/dst IP/port from/to named sets,\n"
+ " where flags are the comma separated list of\n"
+ " 'src' and 'dst' specifications.\n");
+}
+
+static const struct option set_target_opts_v2[] = {
+ {.name = "add-set", .has_arg = true, .val = '1'},
+ {.name = "del-set", .has_arg = true, .val = '2'},
+ {.name = "exist", .has_arg = false, .val = '3'},
+ {.name = "timeout", .has_arg = true, .val = '4'},
+ XT_GETOPT_TABLEEND,
+};
+
+static void
+set_target_check_v2(unsigned int flags)
+{
+ if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL)))
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify either `--add-set' or `--del-set'");
+ if (!(flags & SET_TARGET_ADD)) {
+ if (flags & SET_TARGET_EXIST)
+ xtables_error(PARAMETER_PROBLEM,
+ "Flag `--exist' can be used with `--add-set' only");
+ if (flags & SET_TARGET_TIMEOUT)
+ xtables_error(PARAMETER_PROBLEM,
+ "Option `--timeout' can be used with `--add-set' only");
+ }
+}
+
+
+static void
+set_target_init_v2(struct xt_entry_target *target)
{
- const struct xt_set_info_target *info = (const void *)target->data;
+ struct xt_set_info_target_v2 *info =
+ (struct xt_set_info_target_v2 *) target->data;
+
+ info->add_set.index =
+ info->del_set.index = IPSET_INVALID_ID;
+ info->timeout = UINT32_MAX;
+}
+
+static int
+set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct xt_set_info_target_v2 *myinfo =
+ (struct xt_set_info_target_v2 *) (*target)->data;
+ unsigned int timeout;
+
+ switch (c) {
+ case '1': /* --add-set <set> <flags> */
+ parse_target(argv, invert, &myinfo->add_set, "add-set");
+ *flags |= SET_TARGET_ADD;
+ break;
+ case '2': /* --del-set <set>[:<flags>] <flags> */
+ parse_target(argv, invert, &myinfo->del_set, "del-set");
+ *flags |= SET_TARGET_DEL;
+ break;
+ case '3':
+ myinfo->flags |= IPSET_FLAG_EXIST;
+ *flags |= SET_TARGET_EXIST;
+ break;
+ case '4':
+ if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid value for option --timeout "
+ "or out of range 0-%u", UINT32_MAX - 1);
+ myinfo->timeout = timeout;
+ *flags |= SET_TARGET_TIMEOUT;
+ break;
+ }
+ return 1;
+}
+
+static void
+set_target_print_v2(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_set_info_target_v2 *info = (const void *)target->data;
print_target("add-set", &info->add_set);
+ if (info->flags & IPSET_FLAG_EXIST)
+ printf(" exist");
+ if (info->timeout != UINT32_MAX)
+ printf(" timeout %u", info->timeout);
print_target("del-set", &info->del_set);
}
static void
-set_target_save(const void *ip, const struct xt_entry_target *target)
+set_target_save_v2(const void *ip, const struct xt_entry_target *target)
{
- const struct xt_set_info_target *info = (const void *)target->data;
+ const struct xt_set_info_target_v2 *info = (const void *)target->data;
print_target("--add-set", &info->add_set);
+ if (info->flags & IPSET_FLAG_EXIST)
+ printf(" --exist");
+ if (info->timeout != UINT32_MAX)
+ printf(" --timeout %u", info->timeout);
print_target("--del-set", &info->del_set);
}
@@ -248,28 +370,43 @@ static struct xtables_target set_tg_reg[] = {
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
.userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
- .help = set_target_help,
+ .help = set_target_help_v0,
.init = set_target_init_v0,
.parse = set_target_parse_v0,
- .final_check = set_target_check,
+ .final_check = set_target_check_v0,
.print = set_target_print_v0,
.save = set_target_save_v0,
- .extra_opts = set_target_opts,
+ .extra_opts = set_target_opts_v0,
},
{
.name = "SET",
.revision = 1,
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
- .size = XT_ALIGN(sizeof(struct xt_set_info_target)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target)),
- .help = set_target_help,
- .init = set_target_init,
- .parse = set_target_parse,
- .final_check = set_target_check,
- .print = set_target_print,
- .save = set_target_save,
- .extra_opts = set_target_opts,
+ .size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
+ .help = set_target_help_v1,
+ .init = set_target_init_v1,
+ .parse = set_target_parse_v1,
+ .final_check = set_target_check_v1,
+ .print = set_target_print_v1,
+ .save = set_target_save_v1,
+ .extra_opts = set_target_opts_v1,
+ },
+ {
+ .name = "SET",
+ .revision = 2,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_UNSPEC,
+ .size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
+ .help = set_target_help_v2,
+ .init = set_target_init_v2,
+ .parse = set_target_parse_v2,
+ .final_check = set_target_check_v2,
+ .print = set_target_print_v2,
+ .save = set_target_save_v2,
+ .extra_opts = set_target_opts_v2,
},
};
diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man
index ea80c2a1..739be414 100644
--- a/extensions/libxt_SET.man
+++ b/extensions/libxt_SET.man
@@ -12,6 +12,14 @@ where flags are
and/or
.BR "dst"
specifications and there can be no more than six of them.
+.TP
+\fB\-\-timeout\fP \fIvalue\fP
+when adding entry, the timeout value to use instead of the default
+one from the set definition
+.TP
+\fB\-\-exist\fP
+when adding entry if it already exists, reset the timeout value
+to the specified one or to the default from the set definition
.PP
Use of -j SET requires that ipset kernel support is provided. As standard
kernels do not ship this currently, the ipset or Xtables-addons package needs
diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c
index 78bf7c10..da722c73 100644
--- a/extensions/libxt_set.c
+++ b/extensions/libxt_set.c
@@ -22,8 +22,10 @@
#include <linux/netfilter/xt_set.h>
#include "libxt_set.h"
+/* Revision 0 */
+
static void
-set_help(void)
+set_help_v0(void)
{
printf("set match options:\n"
" [!] --match-set name flags\n"
@@ -32,14 +34,14 @@ set_help(void)
" 'src' and 'dst' specifications.\n");
}
-static const struct option set_opts[] = {
+static const struct option set_opts_v0[] = {
{.name = "match-set", .has_arg = true, .val = '1'},
{.name = "set", .has_arg = true, .val = '2'},
XT_GETOPT_TABLEEND,
};
static void
-set_check(unsigned int flags)
+set_check_v0(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
@@ -127,12 +129,18 @@ set_save_v0(const void *ip, const struct xt_entry_match *match)
print_match_v0("--match-set", &info->match_set);
}
+/* Revision 1 */
+
+#define set_help_v1 set_help_v0
+#define set_opts_v1 set_opts_v0
+#define set_check_v1 set_check_v0
+
static int
-set_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
+set_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
{
- struct xt_set_info_match *myinfo =
- (struct xt_set_info_match *) (*match)->data;
+ struct xt_set_info_match_v1 *myinfo =
+ (struct xt_set_info_match_v1 *) (*match)->data;
struct xt_set_info *info = &myinfo->match_set;
switch (c) {
@@ -191,17 +199,17 @@ print_match(const char *prefix, const struct xt_set_info *info)
/* Prints out the matchinfo. */
static void
-set_print(const void *ip, const struct xt_entry_match *match, int numeric)
+set_print_v1(const void *ip, const struct xt_entry_match *match, int numeric)
{
- const struct xt_set_info_match *info = (const void *)match->data;
+ const struct xt_set_info_match_v1 *info = (const void *)match->data;
print_match("match-set", &info->match_set);
}
static void
-set_save(const void *ip, const struct xt_entry_match *match)
+set_save_v1(const void *ip, const struct xt_entry_match *match)
{
- const struct xt_set_info_match *info = (const void *)match->data;
+ const struct xt_set_info_match_v1 *info = (const void *)match->data;
print_match("--match-set", &info->match_set);
}
@@ -214,26 +222,26 @@ static struct xtables_match set_mt_reg[] = {
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
.userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
- .help = set_help,
+ .help = set_help_v0,
.parse = set_parse_v0,
- .final_check = set_check,
+ .final_check = set_check_v0,
.print = set_print_v0,
.save = set_save_v0,
- .extra_opts = set_opts,
+ .extra_opts = set_opts_v0,
},
{
.name = "set",
.revision = 1,
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
- .size = XT_ALIGN(sizeof(struct xt_set_info_match)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match)),
- .help = set_help,
- .parse = set_parse,
- .final_check = set_check,
- .print = set_print,
- .save = set_save,
- .extra_opts = set_opts,
+ .size = XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
+ .help = set_help_v1,
+ .parse = set_parse_v1,
+ .final_check = set_check_v1,
+ .print = set_print_v1,
+ .save = set_save_v1,
+ .extra_opts = set_opts_v1,
},
};
diff --git a/include/linux/netfilter/xt_set.h b/include/linux/netfilter/xt_set.h
index 3ad31378..4379ce9f 100644
--- a/include/linux/netfilter/xt_set.h
+++ b/include/linux/netfilter/xt_set.h
@@ -89,7 +89,7 @@ struct xt_set_info_target_v0 {
struct xt_set_info_v0 del_set;
};
-/* Revision 1: current interface to netfilter/iptables */
+/* Revision 1 match and target */
struct xt_set_info {
ip_set_id_t index;
@@ -98,13 +98,27 @@ struct xt_set_info {
};
/* match and target infos */
-struct xt_set_info_match {
+struct xt_set_info_match_v1 {
struct xt_set_info match_set;
};
-struct xt_set_info_target {
+struct xt_set_info_target_v1 {
struct xt_set_info add_set;
struct xt_set_info del_set;
};
+/* Revision 2 target */
+
+enum ipset_cmd_flags {
+ IPSET_FLAG_BIT_EXIST = 0,
+ IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
+};
+
+struct xt_set_info_target_v2 {
+ struct xt_set_info add_set;
+ struct xt_set_info del_set;
+ u_int32_t flags;
+ u_int32_t timeout;
+};
+
#endif /*_XT_SET_H*/