summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile.am40
-rw-r--r--extensions/GNUmakefile.in59
-rw-r--r--extensions/libxt_SET.c207
-rw-r--r--extensions/libxt_SET.man8
-rw-r--r--extensions/libxt_set.c52
-rw-r--r--extensions/libxt_set.h7
-rw-r--r--include/ip6tables.h8
-rw-r--r--include/iptables.h10
-rw-r--r--include/linux/netfilter/xt_set.h20
-rw-r--r--include/xtables.h.in2
-rw-r--r--ip6tables-multi.c23
-rw-r--r--ip6tables-restore.c5
-rw-r--r--ip6tables-save.c3
-rw-r--r--ip6tables-standalone.c1
-rw-r--r--ip6tables.c47
-rw-r--r--iptables-multi.c26
-rw-r--r--iptables-restore.c9
-rw-r--r--iptables-save.c3
-rw-r--r--iptables-standalone.c3
-rw-r--r--iptables-xml.c2
-rw-r--r--iptables.c48
-rw-r--r--xshared.h2
-rw-r--r--xtables-multi.c39
-rw-r--r--xtables.c104
25 files changed, 512 insertions, 220 deletions
diff --git a/.gitignore b/.gitignore
index e5d30996..9d24ce0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ Makefile
Makefile.in
/extensions/GNUmakefile
+/extensions/initext.c
/extensions/initext?.c
/extensions/matches?.man
/extensions/targets?.man
@@ -40,14 +41,13 @@ Makefile.in
/ip6tables
/ip6tables.8
-/ip6tables-multi
/ip6tables-save
/ip6tables-restore
/ip6tables-static
/iptables
/iptables.8
-/iptables-multi
/iptables-save
/iptables-restore
/iptables-static
/iptables-xml
+/xtables-multi
diff --git a/Makefile.am b/Makefile.am
index fbed41fc..13e144e4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,7 +17,7 @@ endif
lib_LTLIBRARIES =
# libiptc
-lib_LTLIBRARIES += libiptc/libip4tc.la libiptc/libip6tc.la libiptc/libiptc.la
+lib_LTLIBRARIES += libiptc/libip4tc.la libiptc/libip6tc.la libiptc/libiptc.la
libiptc_libiptc_la_SOURCES =
libiptc_libiptc_la_LIBADD = libiptc/libip4tc.la libiptc/libip6tc.la
libiptc_libiptc_la_LDFLAGS = -version-info 0:0:0 ${libiptc_LDFLAGS2}
@@ -37,39 +37,39 @@ libxtables_la_CFLAGS = ${AM_CFLAGS} -DNO_SHARED_LIBS=1
libxtables_la_LIBADD =
endif
-iptables_multi_SOURCES = iptables-multi.c iptables-save.c \
- iptables-restore.c iptables-xml.c \
- iptables-standalone.c iptables.c xshared.c
-iptables_multi_CFLAGS = ${AM_CFLAGS} -DIPTABLES_MULTI
+xtables_multi_SOURCES = xtables-multi.c
+xtables_multi_CFLAGS = ${AM_CFLAGS} -DIPTABLES_MULTI
+xtables_multi_LDFLAGS = -rdynamic
+xtables_multi_LDADD = extensions/libext.a
if ENABLE_STATIC
-iptables_multi_CFLAGS += -DALL_INCLUSIVE
+xtables_multi_CFLAGS += -DALL_INCLUSIVE
endif
-iptables_multi_LDFLAGS = -rdynamic
-iptables_multi_LDADD = libiptc/libip4tc.la extensions/libext4.a libxtables.la -lm
-
-ip6tables_multi_SOURCES = ip6tables-multi.c ip6tables-save.c \
- ip6tables-restore.c ip6tables-standalone.c \
- ip6tables.c xshared.c
-ip6tables_multi_CFLAGS = ${AM_CFLAGS} -DIPTABLES_MULTI
-if ENABLE_STATIC
-ip6tables_multi_CFLAGS += -DALL_INCLUSIVE
+if ENABLE_IPV4
+xtables_multi_SOURCES += iptables-save.c iptables-restore.c iptables-xml.c \
+ iptables-standalone.c iptables.c
+xtables_multi_CFLAGS += -DENABLE_IPV4
+xtables_multi_LDADD += libiptc/libip4tc.la extensions/libext4.a
+endif
+if ENABLE_IPV6
+xtables_multi_SOURCES += ip6tables-save.c ip6tables-restore.c \
+ ip6tables-standalone.c ip6tables.c
+xtables_multi_CFLAGS += -DENABLE_IPV6
+xtables_multi_LDADD += libiptc/libip6tc.la extensions/libext6.a
endif
-ip6tables_multi_LDFLAGS = -rdynamic
-ip6tables_multi_LDADD = libiptc/libip6tc.la extensions/libext6.a libxtables.la -lm
+xtables_multi_SOURCES += xshared.c
+xtables_multi_LDADD += libxtables.la -lm
-sbin_PROGRAMS =
+sbin_PROGRAMS = xtables-multi
man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
iptables-xml.8 ip6tables.8 ip6tables-restore.8 \
ip6tables-save.8
CLEANFILES = iptables.8 ip6tables.8
if ENABLE_IPV4
-sbin_PROGRAMS += iptables-multi
v4_bin_links = iptables-xml
v4_sbin_links = iptables iptables-restore iptables-save
endif
if ENABLE_IPV6
-sbin_PROGRAMS += ip6tables-multi
v6_sbin_links = ip6tables ip6tables-restore ip6tables-save
endif
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index b96bd11f..a511a39a 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -51,11 +51,13 @@ pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod})
#
# Building blocks
#
-targets := libext4.a libext6.a matches4.man matches6.man \
+targets := libext.a libext4.a libext6.a \
+ matches4.man matches6.man \
targets4.man targets6.man
targets_install :=
-@ENABLE_STATIC_TRUE@ libext4_objs := ${pfx_objs} ${pf4_objs}
-@ENABLE_STATIC_TRUE@ libext6_objs := ${pfx_objs} ${pf6_objs}
+@ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs}
+@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs}
+@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs}
@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
@@ -70,7 +72,7 @@ install: ${targets_install}
if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi;
clean:
- rm -f *.o *.oo *.so *.a {matches,targets}[46].man initext4.c initext6.c;
+ rm -f *.o *.oo *.so *.a {matches,targets}[46].man initext.c initext4.c initext6.c;
distclean: clean
rm -f .*.d .*.dd;
@@ -101,26 +103,35 @@ lib%.oo: ${srcdir}/lib%.c
lib%.o: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
+libext.a: initext.o ${libext_objs}
+ ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+
libext4.a: initext4.o ${libext4_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
libext6.a: initext6.o ${libext6_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
-initext_func := $(addprefix xt_,${pfx_build_mod}) $(addprefix ipt_,${pf4_build_mod})
-initext6_func := $(addprefix xt_,${pfx_build_mod}) $(addprefix ip6t_,${pf6_build_mod})
+initext_func := $(addprefix xt_,${pfx_build_mod})
+initext4_func := $(addprefix ipt_,${pf4_build_mod})
+initext6_func := $(addprefix ip6t_,${pf6_build_mod})
-.initext4.dd: FORCE
+.initext.dd: FORCE
@echo "${initext_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
+.initext4.dd: FORCE
+ @echo "${initext4_func}" >$@.tmp; \
+ cmp -s $@ $@.tmp || mv $@.tmp $@; \
+ rm -f $@.tmp;
+
.initext6.dd: FORCE
@echo "${initext6_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
-initext4.c: .initext4.dd
+initext.c: .initext.dd
${AM_VERBOSE_GEN}
@( \
echo "" >$@; \
@@ -136,6 +147,22 @@ initext4.c: .initext4.dd
echo "}" >>$@; \
);
+initext4.c: .initext4.dd
+ ${AM_VERBOSE_GEN}
+ @( \
+ echo "" >$@; \
+ for i in ${initext4_func}; do \
+ echo "extern void lib$${i}_init(void);" >>$@; \
+ done; \
+ echo "void init_extensions4(void);" >>$@; \
+ echo "void init_extensions4(void)" >>$@; \
+ echo "{" >>$@; \
+ for i in ${initext4_func}; do \
+ echo " ""lib$${i}_init();" >>$@; \
+ done; \
+ echo "}" >>$@; \
+ );
+
initext6.c: .initext6.dd
${AM_VERBOSE_GEN}
@( \
@@ -143,8 +170,8 @@ initext6.c: .initext6.dd
for i in ${initext6_func}; do \
echo "extern void lib$${i}_init(void);" >>$@; \
done; \
- echo "void init_extensions(void);" >>$@; \
- echo "void init_extensions(void)" >>$@; \
+ echo "void init_extensions6(void);" >>$@; \
+ echo "void init_extensions6(void)" >>$@; \
echo "{" >>$@; \
for i in ${initext6_func}; do \
echo " ""lib$${i}_init();" >>$@; \
@@ -155,8 +182,8 @@ initext6.c: .initext6.dd
#
# Manual pages
#
-ex_matches = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:alnum:]_]+\b'))
-ex_targets = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:alnum:]_]+\b'))
+ex_matches = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:lower:][:digit:]_]+\b'))
+ex_targets = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:upper:][:digit:]_]+\b'))
man_run = \
${AM_VERBOSE_GEN} \
for ext in $(1); do \
@@ -177,14 +204,14 @@ man_run = \
fi; \
done >$@;
-matches4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man)
+matches4.man: .initext.dd .initext4.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4)
-matches6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man)
+matches6.man: .initext.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6)
-targets4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man)
+targets4.man: .initext.dd .initext4.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4)
-targets6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man)
+targets6.man: .initext.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6)
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/extensions/libxt_set.h b/extensions/libxt_set.h
index 6b936911..4ac84fa9 100644
--- a/extensions/libxt_set.h
+++ b/extensions/libxt_set.h
@@ -114,7 +114,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
if (tmp)
xtables_error(PARAMETER_PROBLEM,
"Can't be more src/dst options than %i.",
- IPSET_DIM_MAX - 1);
+ IPSET_DIM_MAX);
free(saved);
}
@@ -124,9 +124,8 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info)
{
char *saved = strdup(opt_arg);
char *ptr, *tmp = saved;
- int i = 0;
- while (i < (IPSET_DIM_MAX - 1) && tmp != NULL) {
+ while (info->dim < IPSET_DIM_MAX && tmp != NULL) {
info->dim++;
ptr = strsep(&tmp, ",");
if (strncmp(ptr, "src", 3) == 0)
@@ -139,7 +138,7 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info)
if (tmp)
xtables_error(PARAMETER_PROBLEM,
"Can't be more src/dst options than %i.",
- IPSET_DIM_MAX - 1);
+ IPSET_DIM_MAX);
free(saved);
}
diff --git a/include/ip6tables.h b/include/ip6tables.h
index ca0f9a05..e976361f 100644
--- a/include/ip6tables.h
+++ b/include/ip6tables.h
@@ -10,10 +10,10 @@
extern int do_command6(int argc, char *argv[], char **table,
struct ip6tc_handle **handle);
-extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *), int verbose, int builtinstoo, struct ip6tc_handle *handle);
-extern int flush_entries(const ip6t_chainlabel chain, int verbose, struct ip6tc_handle *handle);
-extern int delete_chain(const ip6t_chainlabel chain, int verbose, struct ip6tc_handle *handle);
-void print_rule(const struct ip6t_entry *e, struct ip6tc_handle *h, const char *chain, int counters);
+extern int for_each_chain6(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *), int verbose, int builtinstoo, struct ip6tc_handle *handle);
+extern int flush_entries6(const ip6t_chainlabel chain, int verbose, struct ip6tc_handle *handle);
+extern int delete_chain6(const ip6t_chainlabel chain, int verbose, struct ip6tc_handle *handle);
+void print_rule6(const struct ip6t_entry *e, struct ip6tc_handle *h, const char *chain, int counters);
extern struct xtables_globals ip6tables_globals;
diff --git a/include/iptables.h b/include/iptables.h
index 84211c32..65b32909 100644
--- a/include/iptables.h
+++ b/include/iptables.h
@@ -7,15 +7,15 @@
#include <iptables/internal.h>
/* Your shared library should call one of these. */
-extern int do_command(int argc, char *argv[], char **table,
+extern int do_command4(int argc, char *argv[], char **table,
struct iptc_handle **handle);
-extern int delete_chain(const ipt_chainlabel chain, int verbose,
+extern int delete_chain4(const ipt_chainlabel chain, int verbose,
struct iptc_handle *handle);
-extern int flush_entries(const ipt_chainlabel chain, int verbose,
+extern int flush_entries4(const ipt_chainlabel chain, int verbose,
struct iptc_handle *handle);
-extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
+extern int for_each_chain4(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
int verbose, int builtinstoo, struct iptc_handle *handle);
-extern void print_rule(const struct ipt_entry *e,
+extern void print_rule4(const struct ipt_entry *e,
struct iptc_handle *handle, const char *chain, int counters);
/* kernel revision handling */
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*/
diff --git a/include/xtables.h.in b/include/xtables.h.in
index 47f797bd..eb088b6b 100644
--- a/include/xtables.h.in
+++ b/include/xtables.h.in
@@ -435,6 +435,8 @@ extern void xtables_save_string(const char *value);
# define _init _INIT
# endif
extern void init_extensions(void);
+ extern void init_extensions4(void);
+ extern void init_extensions6(void);
#else
# define _init __attribute__((constructor)) _INIT
#endif
diff --git a/ip6tables-multi.c b/ip6tables-multi.c
deleted file mode 100644
index 7e6603f8..00000000
--- a/ip6tables-multi.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "xshared.h"
-
-int ip6tables_main(int argc, char **argv);
-int ip6tables_save_main(int argc, char **argv);
-int ip6tables_restore_main(int argc, char **argv);
-
-static const struct subcommand multi6_subcommands[] = {
- {"ip6tables", ip6tables_main},
- {"main", ip6tables_main},
- {"ip6tables-save", ip6tables_save_main},
- {"save", ip6tables_save_main},
- {"ip6tables-restore", ip6tables_restore_main},
- {"restore", ip6tables_restore_main},
- {NULL},
-};
-
-int main(int argc, char **argv)
-{
- return subcmd_main(argc, argv, multi6_subcommands);
-}
diff --git a/ip6tables-restore.c b/ip6tables-restore.c
index 10c3acfc..420bc523 100644
--- a/ip6tables-restore.c
+++ b/ip6tables-restore.c
@@ -138,6 +138,7 @@ int main(int argc, char *argv[])
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions6();
#endif
while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) {
@@ -226,12 +227,12 @@ int main(int argc, char *argv[])
if (noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
- for_each_chain(flush_entries, verbose, 1,
+ for_each_chain6(flush_entries6, verbose, 1,
handle);
DEBUGP("Deleting all user-defined chains "
"of table '%s'\n", table);
- for_each_chain(delete_chain, verbose, 0,
+ for_each_chain6(delete_chain6, verbose, 0,
handle);
}
diff --git a/ip6tables-save.c b/ip6tables-save.c
index c3b8ec0d..39a33256 100644
--- a/ip6tables-save.c
+++ b/ip6tables-save.c
@@ -109,7 +109,7 @@ static int do_output(const char *tablename)
/* Dump out rules */
e = ip6tc_first_rule(chain, h);
while(e) {
- print_rule(e, h, chain, show_counters);
+ print_rule6(e, h, chain, show_counters);
e = ip6tc_next_rule(e, h);
}
}
@@ -150,6 +150,7 @@ int main(int argc, char *argv[])
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions6();
#endif
while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
diff --git a/ip6tables-standalone.c b/ip6tables-standalone.c
index 8661bd9c..9d8d5a0f 100644
--- a/ip6tables-standalone.c
+++ b/ip6tables-standalone.c
@@ -60,6 +60,7 @@ main(int argc, char *argv[])
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions6();
#endif
ret = do_command6(argc, argv, &table, &handle);
diff --git a/ip6tables.c b/ip6tables.c
index 3beeddf6..967a5f80 100644
--- a/ip6tables.c
+++ b/ip6tables.c
@@ -124,15 +124,11 @@ static struct option original_opts[] = {
{.name = "modprobe", .has_arg = 1, .val = 'M'},
{.name = "set-counters", .has_arg = 1, .val = 'c'},
{.name = "goto", .has_arg = 1, .val = 'g'},
+ {.name = "ipv4", .has_arg = 0, .val = '4'},
+ {.name = "ipv6", .has_arg = 0, .val = '6'},
{NULL},
};
-/* we need this for ip6tables-restore. ip6tables-restore.c sets line to the
- * current line of the input file, in order to give a more precise error
- * message. ip6tables itself doesn't need this, so it is initialized to the
- * magic number of -1 */
-int line = -1;
-
void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ip6tables_globals = {
.option_offset = 0,
@@ -254,6 +250,8 @@ exit_printhelp(const struct xtables_rule_match *matches)
" Change chain name, (moving any references)\n"
"Options:\n"
+" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n"
+" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n"
"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n"
"[!] --source -s address[/mask][,...]\n"
" source specification\n"
@@ -859,7 +857,7 @@ check_entry(const ip6t_chainlabel chain, struct ip6t_entry *fw,
}
int
-for_each_chain(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *),
+for_each_chain6(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *),
int verbose, int builtinstoo, struct ip6tc_handle *handle)
{
int ret = 1;
@@ -895,11 +893,11 @@ for_each_chain(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *),
}
int
-flush_entries(const ip6t_chainlabel chain, int verbose,
+flush_entries6(const ip6t_chainlabel chain, int verbose,
struct ip6tc_handle *handle)
{
if (!chain)
- return for_each_chain(flush_entries, verbose, 1, handle);
+ return for_each_chain6(flush_entries6, verbose, 1, handle);
if (verbose)
fprintf(stdout, "Flushing chain `%s'\n", chain);
@@ -911,7 +909,7 @@ zero_entries(const ip6t_chainlabel chain, int verbose,
struct ip6tc_handle *handle)
{
if (!chain)
- return for_each_chain(zero_entries, verbose, 1, handle);
+ return for_each_chain6(zero_entries, verbose, 1, handle);
if (verbose)
fprintf(stdout, "Zeroing chain `%s'\n", chain);
@@ -919,11 +917,11 @@ zero_entries(const ip6t_chainlabel chain, int verbose,
}
int
-delete_chain(const ip6t_chainlabel chain, int verbose,
+delete_chain6(const ip6t_chainlabel chain, int verbose,
struct ip6tc_handle *handle)
{
if (!chain)
- return for_each_chain(delete_chain, verbose, 0, handle);
+ return for_each_chain6(delete_chain6, verbose, 0, handle);
if (verbose)
fprintf(stdout, "Deleting chain `%s'\n", chain);
@@ -1083,7 +1081,7 @@ static void print_ip(const char *prefix, const struct in6_addr *ip,
/* We want this to be readable, so only print out neccessary fields.
* Because that's the kind of world I want to live in. */
-void print_rule(const struct ip6t_entry *e,
+void print_rule6(const struct ip6t_entry *e,
struct ip6tc_handle *h, const char *chain, int counters)
{
const struct ip6t_entry_target *t;
@@ -1215,7 +1213,7 @@ list_rules(const ip6t_chainlabel chain, int rulenum, int counters,
while(e) {
num++;
if (!rulenum || num == rulenum)
- print_rule(e, handle, this, counters);
+ print_rule6(e, handle, this, counters);
e = ip6tc_next_rule(e, handle);
}
found = 1;
@@ -1425,11 +1423,11 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand
cs.jumpto = "";
cs.argv = argv;
- /* re-set optind to 0 in case do_command gets called
+ /* re-set optind to 0 in case do_command6 gets called
* a second time */
optind = 0;
- /* clear mflags in case do_command gets called a second time
+ /* clear mflags in case do_command6 gets called a second time
* (we clear the global list of all matches for security)*/
for (m = xtables_matches; m; m = m->next)
m->mflags = 0;
@@ -1445,7 +1443,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand
opts = xt_params->orig_opts;
while ((cs.c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:",
+ "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:46",
opts, NULL)) != -1) {
switch (cs.c) {
/*
@@ -1762,6 +1760,17 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand
cs.fw6.counters.bcnt = cnt;
break;
+ case '4':
+ /* This is not the IPv4 iptables */
+ if (line != -1)
+ return 1; /* success: line ignored */
+ fprintf(stderr, "This is the IPv6 version of ip6tables.\n");
+ exit_tryhelp(2);
+
+ case '6':
+ /* This is indeed the IPv6 ip6tables */
+ break;
+
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
if (cs.invert)
@@ -1953,7 +1962,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand
*handle);
break;
case CMD_FLUSH:
- ret = flush_entries(chain, cs.options&OPT_VERBOSE, *handle);
+ ret = flush_entries6(chain, cs.options&OPT_VERBOSE, *handle);
break;
case CMD_ZERO:
ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
@@ -1994,7 +2003,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand
ret = ip6tc_create_chain(chain, *handle);
break;
case CMD_DELETE_CHAIN:
- ret = delete_chain(chain, cs.options&OPT_VERBOSE, *handle);
+ ret = delete_chain6(chain, cs.options&OPT_VERBOSE, *handle);
break;
case CMD_RENAME_CHAIN:
ret = ip6tc_rename_chain(chain, newname, *handle);
diff --git a/iptables-multi.c b/iptables-multi.c
deleted file mode 100644
index 754b5873..00000000
--- a/iptables-multi.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "xshared.h"
-
-int iptables_main(int argc, char **argv);
-int iptables_save_main(int argc, char **argv);
-int iptables_restore_main(int argc, char **argv);
-int iptables_xml_main(int argc, char **argv);
-
-static const struct subcommand multi4_subcommands[] = {
- {"iptables", iptables_main},
- {"main", iptables_main},
- {"iptables-save", iptables_save_main},
- {"save", iptables_save_main},
- {"iptables-restore", iptables_restore_main},
- {"restore", iptables_restore_main},
- {"iptables-xml", iptables_xml_main},
- {"xml", iptables_xml_main},
- {NULL},
-};
-
-int main(int argc, char **argv)
-{
- return subcmd_main(argc, argv, multi4_subcommands);
-}
diff --git a/iptables-restore.c b/iptables-restore.c
index c2cc58c8..26245997 100644
--- a/iptables-restore.c
+++ b/iptables-restore.c
@@ -141,6 +141,7 @@ main(int argc, char *argv[])
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions4();
#endif
while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) {
@@ -233,12 +234,12 @@ main(int argc, char *argv[])
if (noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
- for_each_chain(flush_entries, verbose, 1,
+ for_each_chain4(flush_entries4, verbose, 1,
handle);
DEBUGP("Deleting all user-defined chains "
"of table '%s'\n", table);
- for_each_chain(delete_chain, verbose, 0,
+ for_each_chain4(delete_chain4, verbose, 0,
handle);
}
@@ -438,13 +439,13 @@ main(int argc, char *argv[])
}
}
- DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
+ DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
newargc, curtable);
for (a = 0; a < newargc; a++)
DEBUGP("argv[%u]: %s\n", a, newargv[a]);
- ret = do_command(newargc, newargv,
+ ret = do_command4(newargc, newargv,
&newargv[2], &handle);
free_argv();
diff --git a/iptables-save.c b/iptables-save.c
index 3e3ec43c..7542bdc0 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -107,7 +107,7 @@ static int do_output(const char *tablename)
/* Dump out rules */
e = iptc_first_rule(chain, h);
while(e) {
- print_rule(e, h, chain, show_counters);
+ print_rule4(e, h, chain, show_counters);
e = iptc_next_rule(e, h);
}
}
@@ -150,6 +150,7 @@ main(int argc, char *argv[])
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions4();
#endif
while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) {
diff --git a/iptables-standalone.c b/iptables-standalone.c
index 1f60e314..87f1d31a 100644
--- a/iptables-standalone.c
+++ b/iptables-standalone.c
@@ -60,9 +60,10 @@ main(int argc, char *argv[])
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
+ init_extensions4();
#endif
- ret = do_command(argc, argv, &table, &handle);
+ ret = do_command4(argc, argv, &table, &handle);
if (ret) {
ret = iptc_commit(handle);
iptc_free(handle);
diff --git a/iptables-xml.c b/iptables-xml.c
index 57c7486d..dc3cd4f2 100644
--- a/iptables-xml.c
+++ b/iptables-xml.c
@@ -844,7 +844,7 @@ main(int argc, char *argv[])
}
}
- DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
+ DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
newargc, curTable);
for (a = 0; a < newargc; a++)
diff --git a/iptables.c b/iptables.c
index 2c1528ea..cc7525a1 100644
--- a/iptables.c
+++ b/iptables.c
@@ -123,15 +123,11 @@ static struct option original_opts[] = {
{.name = "modprobe", .has_arg = 1, .val = 'M'},
{.name = "set-counters", .has_arg = 1, .val = 'c'},
{.name = "goto", .has_arg = 1, .val = 'g'},
+ {.name = "ipv4", .has_arg = 0, .val = '4'},
+ {.name = "ipv6", .has_arg = 0, .val = '6'},
{NULL},
};
-/* we need this for iptables-restore. iptables-restore.c sets line to the
- * current line of the input file, in order to give a more precise error
- * message. iptables itself doesn't need this, so it is initialized to the
- * magic number of -1 */
-int line = -1;
-
void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals iptables_globals = {
@@ -267,6 +263,8 @@ exit_printhelp(const struct xtables_rule_match *matches)
" Change chain name, (moving any references)\n"
"Options:\n"
+" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
+" --ipv6 -6 Error (line is ignored by iptables-restore)\n"
"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n"
"[!] --source -s address[/mask][...]\n"
" source specification\n"
@@ -862,7 +860,7 @@ check_entry(const ipt_chainlabel chain, struct ipt_entry *fw,
}
int
-for_each_chain(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
+for_each_chain4(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
int verbose, int builtinstoo, struct iptc_handle *handle)
{
int ret = 1;
@@ -898,11 +896,11 @@ for_each_chain(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *),
}
int
-flush_entries(const ipt_chainlabel chain, int verbose,
+flush_entries4(const ipt_chainlabel chain, int verbose,
struct iptc_handle *handle)
{
if (!chain)
- return for_each_chain(flush_entries, verbose, 1, handle);
+ return for_each_chain4(flush_entries4, verbose, 1, handle);
if (verbose)
fprintf(stdout, "Flushing chain `%s'\n", chain);
@@ -914,7 +912,7 @@ zero_entries(const ipt_chainlabel chain, int verbose,
struct iptc_handle *handle)
{
if (!chain)
- return for_each_chain(zero_entries, verbose, 1, handle);
+ return for_each_chain4(zero_entries, verbose, 1, handle);
if (verbose)
fprintf(stdout, "Zeroing chain `%s'\n", chain);
@@ -922,11 +920,11 @@ zero_entries(const ipt_chainlabel chain, int verbose,
}
int
-delete_chain(const ipt_chainlabel chain, int verbose,
+delete_chain4(const ipt_chainlabel chain, int verbose,
struct iptc_handle *handle)
{
if (!chain)
- return for_each_chain(delete_chain, verbose, 0, handle);
+ return for_each_chain4(delete_chain4, verbose, 0, handle);
if (verbose)
fprintf(stdout, "Deleting chain `%s'\n", chain);
@@ -1101,7 +1099,7 @@ static void print_ip(const char *prefix, uint32_t ip,
/* We want this to be readable, so only print out neccessary fields.
* Because that's the kind of world I want to live in. */
-void print_rule(const struct ipt_entry *e,
+void print_rule4(const struct ipt_entry *e,
struct iptc_handle *h, const char *chain, int counters)
{
const struct ipt_entry_target *t;
@@ -1224,7 +1222,7 @@ list_rules(const ipt_chainlabel chain, int rulenum, int counters,
while(e) {
num++;
if (!rulenum || num == rulenum)
- print_rule(e, handle, this, counters);
+ print_rule4(e, handle, this, counters);
e = iptc_next_rule(e, handle);
}
found = 1;
@@ -1429,7 +1427,7 @@ static void command_match(struct iptables_command_state *cs)
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
}
-int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle)
+int do_command4(int argc, char *argv[], char **table, struct iptc_handle **handle)
{
struct iptables_command_state cs;
struct ipt_entry *e = NULL;
@@ -1453,11 +1451,11 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
cs.jumpto = "";
cs.argv = argv;
- /* re-set optind to 0 in case do_command gets called
+ /* re-set optind to 0 in case do_command4 gets called
* a second time */
optind = 0;
- /* clear mflags in case do_command gets called a second time
+ /* clear mflags in case do_command4 gets called a second time
* (we clear the global list of all matches for security)*/
for (m = xtables_matches; m; m = m->next)
m->mflags = 0;
@@ -1473,7 +1471,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
opts = xt_params->orig_opts;
while ((cs.c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
+ "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46",
opts, NULL)) != -1) {
switch (cs.c) {
/*
@@ -1788,6 +1786,16 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
cs.fw.counters.bcnt = cnt;
break;
+ case '4':
+ /* This is indeed the IPv4 iptables */
+ break;
+
+ case '6':
+ /* This is not the IPv6 ip6tables */
+ if (line != -1)
+ return 1; /* success: line ignored */
+ fprintf(stderr, "This is the IPv4 version of iptables.\n");
+ exit_tryhelp(2);
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
@@ -1989,7 +1997,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
*handle);
break;
case CMD_FLUSH:
- ret = flush_entries(chain, cs.options&OPT_VERBOSE, *handle);
+ ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle);
break;
case CMD_ZERO:
ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
@@ -2030,7 +2038,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
ret = iptc_create_chain(chain, *handle);
break;
case CMD_DELETE_CHAIN:
- ret = delete_chain(chain, cs.options&OPT_VERBOSE, *handle);
+ ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle);
break;
case CMD_RENAME_CHAIN:
ret = iptc_rename_chain(chain, newname, *handle);
diff --git a/xshared.h b/xshared.h
index be53535b..34f3265c 100644
--- a/xshared.h
+++ b/xshared.h
@@ -29,6 +29,7 @@ struct xtables_target;
/**
* xtables_afinfo - protocol family dependent information
* @kmod: kernel module basename (e.g. "ip_tables")
+ * @proc_exists: file which exists in procfs when module already loaded
* @libprefix: prefix of .so library name (e.g. "libipt_")
* @family: nfproto family
* @ipproto: used by setsockopt (e.g. IPPROTO_IP)
@@ -37,6 +38,7 @@ struct xtables_target;
*/
struct xtables_afinfo {
const char *kmod;
+ const char *proc_exists;
const char *libprefix;
uint8_t family;
uint8_t ipproto;
diff --git a/xtables-multi.c b/xtables-multi.c
new file mode 100644
index 00000000..f8d56ce9
--- /dev/null
+++ b/xtables-multi.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xshared.h"
+
+#ifdef ENABLE_IPV4
+#include "iptables-multi.h"
+#endif
+
+#ifdef ENABLE_IPV6
+#include "ip6tables-multi.h"
+#endif
+
+static const struct subcommand multi_subcommands[] = {
+#ifdef ENABLE_IPV4
+ {"iptables", iptables_main},
+ {"main4", iptables_main},
+ {"iptables-save", iptables_save_main},
+ {"save4", iptables_save_main},
+ {"iptables-restore", iptables_restore_main},
+ {"restore4", iptables_restore_main},
+ {"iptables-xml", iptables_xml_main},
+ {"xml4", iptables_xml_main},
+#endif
+#ifdef ENABLE_IPV6
+ {"ip6tables", ip6tables_main},
+ {"main6", ip6tables_main},
+ {"ip6tables-save", ip6tables_save_main},
+ {"save6", ip6tables_save_main},
+ {"ip6tables-restore", ip6tables_restore_main},
+ {"restore6", ip6tables_restore_main},
+#endif
+ {NULL},
+};
+
+int main(int argc, char **argv)
+{
+ return subcmd_main(argc, argv, multi_subcommands);
+}
diff --git a/xtables.c b/xtables.c
index 90161025..9038f892 100644
--- a/xtables.c
+++ b/xtables.c
@@ -27,9 +27,11 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
+#include <linux/magic.h> /* for PROC_SUPER_MAGIC */
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
@@ -58,6 +60,12 @@
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
#endif
+/* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
+ * current line of the input file, in order to give a more precise error
+ * message. ip6?tables itself doesn't need this, so it is initialized to the
+ * magic number of -1 */
+int line = -1;
+
void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals *xt_params = NULL;
@@ -133,6 +141,7 @@ struct option *xtables_merge_options(struct option *orig_opts,
static const struct xtables_afinfo afinfo_ipv4 = {
.kmod = "ip_tables",
+ .proc_exists = "/proc/net/ip_tables_names",
.libprefix = "libipt_",
.family = NFPROTO_IPV4,
.ipproto = IPPROTO_IP,
@@ -142,6 +151,7 @@ static const struct xtables_afinfo afinfo_ipv4 = {
static const struct xtables_afinfo afinfo_ipv6 = {
.kmod = "ip6_tables",
+ .proc_exists = "/proc/net/ip6_tables_names",
.libprefix = "libip6t_",
.family = NFPROTO_IPV6,
.ipproto = IPPROTO_IPV6,
@@ -157,10 +167,18 @@ static const char *xtables_libdir;
/* the path to command to load kernel module */
const char *xtables_modprobe_program;
-/* Keeping track of external matches and targets: linked lists. */
+/* Keep track of matches/targets pending full registration: linked lists. */
+struct xtables_match *xtables_pending_matches;
+struct xtables_target *xtables_pending_targets;
+
+/* Keep track of fully registered external matches/targets: linked lists. */
struct xtables_match *xtables_matches;
struct xtables_target *xtables_targets;
+/* Fully register a match/target which was previously partially registered. */
+static void xtables_fully_register_pending_match(struct xtables_match *me);
+static void xtables_fully_register_pending_target(struct xtables_target *me);
+
void xtables_init(void)
{
xtables_libdir = getenv("XTABLES_LIBDIR");
@@ -355,15 +373,39 @@ int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
return -1;
}
+/* return true if a given file exists within procfs */
+static bool proc_file_exists(const char *filename)
+{
+ struct stat s;
+ struct statfs f;
+
+ if (lstat(filename, &s))
+ return false;
+ if (!S_ISREG(s.st_mode))
+ return false;
+ if (statfs(filename, &f))
+ return false;
+ if (f.f_type != PROC_SUPER_MAGIC)
+ return false;
+ return true;
+}
+
int xtables_load_ko(const char *modprobe, bool quiet)
{
static bool loaded = false;
- static int ret = -1;
+ int ret;
- if (!loaded) {
- ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
- loaded = (ret == 0);
- }
+ if (loaded)
+ return 0;
+
+ if (proc_file_exists(afinfo->proc_exists)) {
+ loaded = true;
+ return 0;
+ };
+
+ ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
+ if (ret == 0)
+ loaded = true;
return ret;
}
@@ -539,6 +581,7 @@ struct xtables_match *
xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_rule_match **matches)
{
+ struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
@@ -554,6 +597,18 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
(strcmp(name,"icmp6") == 0) )
name = icmp6;
+ /* Trigger delayed initialization */
+ for (dptr = &xtables_pending_matches; *dptr; ) {
+ if (strcmp(name, (*dptr)->name) == 0) {
+ ptr = *dptr;
+ *dptr = (*dptr)->next;
+ ptr->next = NULL;
+ xtables_fully_register_pending_match(ptr);
+ } else {
+ dptr = &((*dptr)->next);
+ }
+ }
+
for (ptr = xtables_matches; ptr; ptr = ptr->next) {
if (strcmp(name, ptr->name) == 0) {
struct xtables_match *clone;
@@ -619,6 +674,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_target *
xtables_find_target(const char *name, enum xtables_tryload tryload)
{
+ struct xtables_target **dptr;
struct xtables_target *ptr;
/* Standard target? */
@@ -629,6 +685,18 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
|| strcmp(name, XTC_LABEL_RETURN) == 0)
name = "standard";
+ /* Trigger delayed initialization */
+ for (dptr = &xtables_pending_targets; *dptr; ) {
+ if (strcmp(name, (*dptr)->name) == 0) {
+ ptr = *dptr;
+ *dptr = (*dptr)->next;
+ ptr->next = NULL;
+ xtables_fully_register_pending_target(ptr);
+ } else {
+ dptr = &((*dptr)->next);
+ }
+ }
+
for (ptr = xtables_targets; ptr; ptr = ptr->next) {
if (strcmp(name, ptr->name) == 0)
break;
@@ -740,8 +808,6 @@ static void xtables_check_options(const char *name, const struct option *opt)
void xtables_register_match(struct xtables_match *me)
{
- struct xtables_match **i, *old;
-
if (me->version == NULL) {
fprintf(stderr, "%s: match %s<%u> is missing a version\n",
xt_params->program_name, me->name, me->revision);
@@ -777,6 +843,15 @@ void xtables_register_match(struct xtables_match *me)
if (me->family != afinfo->family && me->family != AF_UNSPEC)
return;
+ /* place on linked list of matches pending full registration */
+ me->next = xtables_pending_matches;
+ xtables_pending_matches = me;
+}
+
+static void xtables_fully_register_pending_match(struct xtables_match *me)
+{
+ struct xtables_match **i, *old;
+
old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
if (old) {
if (old->revision == me->revision &&
@@ -830,8 +905,6 @@ void xtables_register_matches(struct xtables_match *match, unsigned int n)
void xtables_register_target(struct xtables_target *me)
{
- struct xtables_target *old;
-
if (me->version == NULL) {
fprintf(stderr, "%s: target %s<%u> is missing a version\n",
xt_params->program_name, me->name, me->revision);
@@ -867,6 +940,15 @@ void xtables_register_target(struct xtables_target *me)
if (me->family != afinfo->family && me->family != AF_UNSPEC)
return;
+ /* place on linked list of targets pending full registration */
+ me->next = xtables_pending_targets;
+ xtables_pending_targets = me;
+}
+
+static void xtables_fully_register_pending_target(struct xtables_target *me)
+{
+ struct xtables_target *old;
+
old = xtables_find_target(me->name, XTF_DURING_LOAD);
if (old) {
struct xtables_target **i;
@@ -1323,7 +1405,7 @@ void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
{
- /* 0000:0000:0000:0000:0000:000.000.000.000
+ /* 0000:0000:0000:0000:0000:0000:000.000.000.000
* 0000:0000:0000:0000:0000:0000:0000:0000 */
static char buf[50+1];
return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));