summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac8
-rw-r--r--extensions/libip6t_srh.t4
-rw-r--r--extensions/libipt_ULOG.c1
-rw-r--r--extensions/libxt_CT.c16
-rw-r--r--extensions/libxt_IDLETIMER.c99
-rw-r--r--extensions/libxt_IDLETIMER.t1
-rw-r--r--extensions/libxt_MARK.man4
-rw-r--r--extensions/libxt_NOTRACK.t3
-rw-r--r--extensions/libxt_NOTRACK.txlate2
-rw-r--r--extensions/libxt_addrtype.c1
-rw-r--r--extensions/libxt_bpf.c26
-rw-r--r--extensions/libxt_connlabel.c7
-rw-r--r--include/linux/netfilter/xt_IDLETIMER.h12
-rw-r--r--include/linux/netfilter/xt_sctp.h6
-rw-r--r--include/xtables.h1
-rwxr-xr-xiptables-test.py7
-rw-r--r--iptables/Makefile.am2
-rw-r--r--iptables/ip6tables-standalone.c2
-rw-r--r--iptables/iptables-restore.c18
-rw-r--r--iptables/iptables-save.c14
-rw-r--r--iptables/iptables-standalone.c2
-rw-r--r--iptables/nft-arp.c29
-rw-r--r--iptables/nft-bridge.c50
-rw-r--r--iptables/nft-cache.c384
-rw-r--r--iptables/nft-cache.h6
-rw-r--r--iptables/nft-cmd.c395
-rw-r--r--iptables/nft-cmd.h79
-rw-r--r--iptables/nft-ipv4.c4
-rw-r--r--iptables/nft-ipv6.c4
-rw-r--r--iptables/nft-shared.c43
-rw-r--r--iptables/nft-shared.h6
-rw-r--r--iptables/nft.c454
-rw-r--r--iptables/nft.h68
-rwxr-xr-xiptables/tests/shell/run-tests.sh47
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-return-codes_01
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0001load-specific-table_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0004-restore-race_05
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_01
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0012-dash-F_012
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0013-test-mode_07
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_06
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0006-46-args_088
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0006-policy-override_029
-rw-r--r--iptables/xshared.c1
-rw-r--r--iptables/xshared.h1
-rw-r--r--iptables/xtables-arp-standalone.c1
-rw-r--r--iptables/xtables-arp.c49
-rw-r--r--iptables/xtables-eb-standalone.c2
-rw-r--r--iptables/xtables-eb.c55
-rw-r--r--iptables/xtables-monitor.c4
-rw-r--r--iptables/xtables-restore.c157
-rw-r--r--iptables/xtables-save.c24
-rw-r--r--iptables/xtables-standalone.c7
-rw-r--r--iptables/xtables-translate.c4
-rw-r--r--iptables/xtables.c95
-rw-r--r--libiptc/libip4tc.c2
-rw-r--r--libiptc/libip6tc.c2
-rw-r--r--libxtables/xtables.c44
-rw-r--r--utils/nfnl_osf.c21
59 files changed, 1684 insertions, 741 deletions
diff --git a/configure.ac b/configure.ac
index 27e90703..31a8bb26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.4])
+AC_INIT([iptables], [1.8.5])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=14
-libxtables_vage=2
+libxtables_vcurrent=15
+libxtables_vage=3
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
@@ -131,7 +131,7 @@ if test "x$enable_nftables" = "xyes"; then
exit 1
fi
- PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.5], [nftables=1], [nftables=0])
+ PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.6], [nftables=1], [nftables=0])
if test "$nftables" = 0;
then
diff --git a/extensions/libip6t_srh.t b/extensions/libip6t_srh.t
index 07b54031..5b02a71b 100644
--- a/extensions/libip6t_srh.t
+++ b/extensions/libip6t_srh.t
@@ -23,6 +23,6 @@
-m srh ! --srh-tag 0;=;OK
-m srh --srh-next-hdr 17 --srh-segs-left-eq 1 --srh-last-entry-eq 4 --srh-tag 0;=;OK
-m srh ! --srh-next-hdr 17 ! --srh-segs-left-eq 0 --srh-tag 0;=;OK
--m srh --srh-psid A::/64 --srh-nsid B:: --srh-lsid C::/0;;OK
--m srh ! --srh-psid A::/64 ! --srh-nsid B:: ! --srh-lsid C::/0;;OK
+-m srh --srh-psid a::/64 --srh-nsid b::/128 --srh-lsid c::/0;=;OK
+-m srh ! --srh-psid a::/64 ! --srh-nsid b::/128 ! --srh-lsid c::/0;=;OK
-m srh;=;OK
diff --git a/extensions/libipt_ULOG.c b/extensions/libipt_ULOG.c
index fafb220b..5163eea3 100644
--- a/extensions/libipt_ULOG.c
+++ b/extensions/libipt_ULOG.c
@@ -11,6 +11,7 @@
*/
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <xtables.h>
/* For 64bit kernel / 32bit userspace */
#include <linux/netfilter_ipv4/ipt_ULOG.h>
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
index 371b2176..fbbbe266 100644
--- a/extensions/libxt_CT.c
+++ b/extensions/libxt_CT.c
@@ -348,6 +348,20 @@ static void notrack_ct2_tg_init(struct xt_entry_target *target)
info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS;
}
+static int xlate_ct1_tg(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct xt_ct_target_info_v1 *info =
+ (struct xt_ct_target_info_v1 *)params->target->data;
+
+ if (info->flags & XT_CT_NOTRACK)
+ xt_xlate_add(xl, "notrack");
+ else
+ return 0;
+
+ return 1;
+}
+
static struct xtables_target ct_target_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -387,6 +401,7 @@ static struct xtables_target ct_target_reg[] = {
.alias = ct_print_name_alias,
.x6_parse = ct_parse_v1,
.x6_options = ct_opts_v1,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
@@ -418,6 +433,7 @@ static struct xtables_target ct_target_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
.init = notrack_ct2_tg_init,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
diff --git a/extensions/libxt_IDLETIMER.c b/extensions/libxt_IDLETIMER.c
index 21004a4b..216b6257 100644
--- a/extensions/libxt_IDLETIMER.c
+++ b/extensions/libxt_IDLETIMER.c
@@ -27,6 +27,7 @@
enum {
O_TIMEOUT = 0,
O_LABEL,
+ O_ALARM,
};
#define s struct idletimer_tg_info
@@ -39,6 +40,17 @@ static const struct xt_option_entry idletimer_tg_opts[] = {
};
#undef s
+#define s struct idletimer_tg_info_v1
+static const struct xt_option_entry idletimer_tg_opts_v1[] = {
+ {.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_UINT32,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, timeout)},
+ {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, label)},
+ {.name = "alarm", .id = O_ALARM, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+#undef s
+
static void idletimer_tg_help(void)
{
printf(
@@ -48,6 +60,16 @@ static void idletimer_tg_help(void)
"\n");
}
+static void idletimer_tg_help_v1(void)
+{
+ printf(
+"IDLETIMER target options:\n"
+" --timeout time Timeout until the notification is sent (in seconds)\n"
+" --label string Unique rule identifier\n"
+" --alarm Use alarm instead of default timer\n"
+"\n");
+}
+
static void idletimer_tg_print(const void *ip,
const struct xt_entry_target *target,
int numeric)
@@ -59,6 +81,20 @@ static void idletimer_tg_print(const void *ip,
printf(" label:%s", info->label);
}
+static void idletimer_tg_print_v1(const void *ip,
+ const struct xt_entry_target *target,
+ int numeric)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" timeout:%u", info->timeout);
+ printf(" label:%s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" alarm");
+}
+
+
static void idletimer_tg_save(const void *ip,
const struct xt_entry_target *target)
{
@@ -69,21 +105,58 @@ static void idletimer_tg_save(const void *ip,
printf(" --label %s", info->label);
}
-static struct xtables_target idletimer_tg_reg = {
- .family = NFPROTO_UNSPEC,
- .name = "IDLETIMER",
- .version = XTABLES_VERSION,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
- .userspacesize = offsetof(struct idletimer_tg_info, timer),
- .help = idletimer_tg_help,
- .x6_parse = xtables_option_parse,
- .print = idletimer_tg_print,
- .save = idletimer_tg_save,
- .x6_options = idletimer_tg_opts,
+static void idletimer_tg_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" --timeout %u", info->timeout);
+ printf(" --label %s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" --alarm");
+}
+
+static void idletimer_tg_parse_v1(struct xt_option_call *cb)
+{
+ struct idletimer_tg_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_ALARM)
+ info->timer_type = XT_IDLETIMER_ALARM;
+}
+
+static struct xtables_target idletimer_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
+ .userspacesize = offsetof(struct idletimer_tg_info, timer),
+ .help = idletimer_tg_help,
+ .x6_parse = xtables_option_parse,
+ .print = idletimer_tg_print,
+ .save = idletimer_tg_save,
+ .x6_options = idletimer_tg_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info_v1)),
+ .userspacesize = offsetof(struct idletimer_tg_info_v1, timer),
+ .help = idletimer_tg_help_v1,
+ .x6_parse = idletimer_tg_parse_v1,
+ .print = idletimer_tg_print_v1,
+ .save = idletimer_tg_save_v1,
+ .x6_options = idletimer_tg_opts_v1,
+ },
+
};
void _init(void)
{
- xtables_register_target(&idletimer_tg_reg);
+ xtables_register_targets(idletimer_tg_reg, ARRAY_SIZE(idletimer_tg_reg));
}
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
index 6afd92c1..e8f306d2 100644
--- a/extensions/libxt_IDLETIMER.t
+++ b/extensions/libxt_IDLETIMER.t
@@ -2,3 +2,4 @@
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
+-j IDLETIMER --timeout 42 --label foo --alarm;;OK
diff --git a/extensions/libxt_MARK.man b/extensions/libxt_MARK.man
index 712fb76f..b2408597 100644
--- a/extensions/libxt_MARK.man
+++ b/extensions/libxt_MARK.man
@@ -1,7 +1,7 @@
This target is used to set the Netfilter mark value associated with the packet.
It can, for example, be used in conjunction with routing based on fwmark (needs
-iproute2). If you plan on doing so, note that the mark needs to be set in the
-PREROUTING chain of the mangle table to affect routing.
+iproute2). If you plan on doing so, note that the mark needs to be set in
+either the PREROUTING or the OUTPUT chain of the mangle table to affect routing.
The mark field is 32 bits wide.
.TP
\fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t
index 585be82d..27c4734f 100644
--- a/extensions/libxt_NOTRACK.t
+++ b/extensions/libxt_NOTRACK.t
@@ -1,4 +1,3 @@
:PREROUTING,OUTPUT
*raw
-# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
-#-j NOTRACK;=;OK
+-j NOTRACK;=;OK
diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate
new file mode 100644
index 00000000..9d35619d
--- /dev/null
+++ b/extensions/libxt_NOTRACK.txlate
@@ -0,0 +1,2 @@
+iptables-translate -A PREROUTING -t raw -j NOTRACK
+nft add rule ip raw PREROUTING counter notrack
diff --git a/extensions/libxt_addrtype.c b/extensions/libxt_addrtype.c
index 27485405..5cafa219 100644
--- a/extensions/libxt_addrtype.c
+++ b/extensions/libxt_addrtype.c
@@ -5,6 +5,7 @@
* This program is released under the terms of GNU GPL */
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <xtables.h>
#include <linux/netfilter/xt_addrtype.h>
diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
index 92958247..eeae86e5 100644
--- a/extensions/libxt_bpf.c
+++ b/extensions/libxt_bpf.c
@@ -61,14 +61,26 @@ static const struct xt_option_entry bpf_opts_v1[] = {
XTOPT_TABLEEND,
};
-static int bpf_obj_get(const char *filepath)
+static int bpf_obj_get_readonly(const char *filepath)
{
#if defined HAVE_LINUX_BPF_H && defined __NR_bpf && defined BPF_FS_MAGIC
- union bpf_attr attr;
-
- memset(&attr, 0, sizeof(attr));
- attr.pathname = (__u64) filepath;
-
+ /* union bpf_attr includes this in an anonymous struct, but the
+ * file_flags field and the BPF_F_RDONLY constant are only present
+ * in Linux 4.15+ kernel headers (include/uapi/linux/bpf.h)
+ */
+ struct { // this part of union bpf_attr is for BPF_OBJ_* commands
+ __aligned_u64 pathname;
+ __u32 bpf_fd;
+ __u32 file_flags;
+ } attr = {
+ .pathname = (__u64)filepath,
+ .file_flags = (1U << 3), // BPF_F_RDONLY
+ };
+ int fd = syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+ if (fd >= 0) return fd;
+
+ /* on any error fallback to default R/W access for pre-4.15-rc1 kernels */
+ attr.file_flags = 0;
return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
#else
xtables_error(OTHER_PROBLEM,
@@ -125,7 +137,7 @@ static void bpf_parse_string(struct sock_filter *pc, __u16 *lenp, __u16 len_max,
static void bpf_parse_obj_pinned(struct xt_bpf_info_v1 *bi,
const char *filepath)
{
- bi->fd = bpf_obj_get(filepath);
+ bi->fd = bpf_obj_get_readonly(filepath);
if (bi->fd < 0)
xtables_error(PARAMETER_PROBLEM,
"bpf: failed to get bpf object");
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index 5a01fe72..565b8c79 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -70,18 +70,15 @@ static int connlabel_value_parse(const char *in)
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
- bool have_labelmap = !connlabel_open();
int tmp;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LABEL:
- if (have_labelmap)
+ tmp = connlabel_value_parse(cb->arg);
+ if (tmp < 0 && !connlabel_open())
tmp = nfct_labelmap_get_bit(map, cb->arg);
- else
- tmp = connlabel_value_parse(cb->arg);
-
if (tmp < 0)
xtables_error(PARAMETER_PROBLEM,
"label '%s' not found or invalid value",
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h
index 208ae938..49ddcdc6 100644
--- a/include/linux/netfilter/xt_IDLETIMER.h
+++ b/include/linux/netfilter/xt_IDLETIMER.h
@@ -32,6 +32,7 @@
#include <linux/types.h>
#define MAX_IDLETIMER_LABEL_SIZE 28
+#define XT_IDLETIMER_ALARM 0x01
struct idletimer_tg_info {
__u32 timeout;
@@ -42,4 +43,15 @@ struct idletimer_tg_info {
struct idletimer_tg *timer __attribute__((aligned(8)));
};
+struct idletimer_tg_info_v1 {
+ __u32 timeout;
+
+ char label[MAX_IDLETIMER_LABEL_SIZE];
+
+ __u8 send_nl_msg; /* unused: for compatibility with Android */
+ __u8 timer_type;
+
+ /* for kernel module internal use only */
+ struct idletimer_tg *timer __attribute__((aligned(8)));
+};
#endif
diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h
index a501e619..5b28525a 100644
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/linux/netfilter/xt_sctp.h
@@ -40,19 +40,19 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] |= \
- 1 << (type % bytes(__u32)); \
+ 1u << (type % bytes(__u32)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] &= \
- ~(1 << (type % bytes(__u32))); \
+ ~(1u << (type % bytes(__u32))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
((chunkmap)[type / bytes (__u32)] & \
- (1 << (type % bytes (__u32)))) ? 1: 0; \
+ (1u << (type % bytes (__u32)))) ? 1: 0; \
})
#define SCTP_CHUNKMAP_RESET(chunkmap) \
diff --git a/include/xtables.h b/include/xtables.h
index 4aa084a1..5044dd08 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -448,6 +448,7 @@ extern struct xtables_match *xtables_matches;
extern struct xtables_target *xtables_targets;
extern void xtables_init(void);
+extern void xtables_fini(void);
extern void xtables_set_nfproto(uint8_t);
extern void *xtables_calloc(size_t, size_t);
extern void *xtables_malloc(size_t);
diff --git a/iptables-test.py b/iptables-test.py
index fdb4e6a3..6b6eb611 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -119,8 +119,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
elif splitted[0] == EBTABLES:
command = EBTABLES_SAVE
- path = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE
- command = path + " " + command
+ command = EXECUTEABLE + " " + command
if netns:
command = "ip netns exec ____iptables-container-test " + command
@@ -165,7 +164,7 @@ def execute_cmd(cmd, filename, lineno):
'''
global log_file
if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '):
- cmd = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE + " " + cmd
+ cmd = EXECUTEABLE + " " + cmd
print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
@@ -222,7 +221,7 @@ def run_test_file(filename, netns):
execute_cmd("ip netns add ____iptables-container-test", filename, 0)
for lineno, line in enumerate(f):
- if line[0] == "#":
+ if line[0] == "#" or len(line.strip()) == 0:
continue
if line[0] == ":":
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 71b1b1d4..dc66b3cc 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -38,7 +38,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-monitor.c nft-cache.c \
xtables-arp-standalone.c xtables-arp.c \
- nft-bridge.c \
+ nft-bridge.c nft-cmd.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
xtables-translate.c
diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c
index 35d2d9a5..105b83ba 100644
--- a/iptables/ip6tables-standalone.c
+++ b/iptables/ip6tables-standalone.c
@@ -64,6 +64,8 @@ ip6tables_main(int argc, char *argv[])
ip6tc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "ip6tables: %s. "
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index b0a51d49..cc2c2b8b 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -178,8 +178,10 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
if (buffer[0] == '\n')
continue;
else if (buffer[0] == '#') {
- if (verbose)
+ if (verbose) {
fputs(buffer, stdout);
+ fflush(stdout);
+ }
continue;
} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
if (!testing) {
@@ -370,7 +372,7 @@ static const struct iptables_restore_cb ipt_restore_cb = {
int
iptables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
iptables_globals.program_name = "iptables-restore";
c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
@@ -385,7 +387,10 @@ iptables_restore_main(int argc, char *argv[])
init_extensions4();
#endif
- return ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
@@ -401,7 +406,7 @@ static const struct iptables_restore_cb ip6t_restore_cb = {
int
ip6tables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
ip6tables_globals.program_name = "ip6tables-restore";
c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
@@ -416,6 +421,9 @@ ip6tables_restore_main(int argc, char *argv[])
init_extensions6();
#endif
- return ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index c7251e35..4efd6667 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -218,6 +218,8 @@ struct iptables_save_cb ipt_save_cb = {
int
iptables_save_main(int argc, char *argv[])
{
+ int ret;
+
iptables_globals.program_name = "iptables-save";
if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -230,7 +232,10 @@ iptables_save_main(int argc, char *argv[])
init_extensions4();
#endif
- return do_iptables_save(&ipt_save_cb, argc, argv);
+ ret = do_iptables_save(&ipt_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV4 */
@@ -259,6 +264,8 @@ struct iptables_save_cb ip6t_save_cb = {
int
ip6tables_save_main(int argc, char *argv[])
{
+ int ret;
+
ip6tables_globals.program_name = "ip6tables-save";
if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -271,6 +278,9 @@ ip6tables_save_main(int argc, char *argv[])
init_extensions6();
#endif
- return do_iptables_save(&ip6t_save_cb, argc, argv);
+ ret = do_iptables_save(&ip6t_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV6 */
diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c
index c211fb73..8c67ea4d 100644
--- a/iptables/iptables-standalone.c
+++ b/iptables/iptables-standalone.c
@@ -64,6 +64,8 @@ iptables_main(int argc, char *argv[])
iptc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "iptables: %s. "
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index d4a86610..67f4529d 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -604,6 +604,8 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
+
+ nft_clear_iptables_command_state(&cs);
}
static bool nft_arp_is_same(const void *data_a,
@@ -633,31 +635,6 @@ static bool nft_arp_is_same(const void *data_a,
(unsigned char *)b->arp.outiface_mask);
}
-static bool nft_arp_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data)
-{
- const struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- /* Delete by matching rule case */
- nft_rule_to_iptables_command_state(h, r, &this);
-
- if (!nft_arp_is_same(&cs->arp, &this.arp))
- goto out;
-
- if (!compare_targets(cs->target, this.target))
- goto out;
-
- if (this.jumpto && strcmp(cs->jumpto, this.jumpto) != 0)
- goto out;
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -675,11 +652,9 @@ struct nft_family_ops nft_family_ops_arp = {
.print_header = nft_arp_print_header,
.print_rule = nft_arp_print_rule,
.save_rule = nft_arp_save_rule,
- .save_counters = save_counters,
.save_chain = nft_arp_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_arp_rule_find,
.parse_target = nft_ipv46_parse_target,
};
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 3f85cbbf..dbf11eb5 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -421,11 +421,20 @@ static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
const struct nftnl_expr *e)
{
const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
+ uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID);
struct nftnl_set_list *slist;
+ struct nftnl_set *set;
slist = nft_set_list_get(ctx->h, ctx->table, set_name);
- if (slist)
- return nftnl_set_list_lookup_byname(slist, set_name);
+ if (slist) {
+ set = nftnl_set_list_lookup_byname(slist, set_name);
+ if (set)
+ return set;
+
+ set = nft_set_batch_lookup_byid(ctx->h, set_id);
+ if (set)
+ return set;
+ }
return NULL;
}
@@ -747,41 +756,6 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b)
return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0;
}
-static bool nft_bridge_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data)
-{
- struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- nft_rule_to_ebtables_command_state(h, r, &this);
-
- DEBUGP("comparing with... ");
-
- if (!nft_bridge_is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
{
int ret = 1, numeric = cs->options & OPT_NUMERIC;
@@ -958,11 +932,9 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_header = nft_bridge_print_header,
.print_rule = nft_bridge_print_rule,
.save_rule = nft_bridge_save_rule,
- .save_counters = save_counters,
.save_chain = nft_bridge_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
- .rule_find = nft_bridge_rule_find,
.xlate = nft_bridge_xlate,
};
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 7345a27e..638b18bc 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -11,6 +11,7 @@
#include <assert.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <xtables.h>
@@ -24,6 +25,52 @@
#include "nft.h"
#include "nft-cache.h"
+static void cache_chain_list_insert(struct list_head *list, const char *name)
+{
+ struct cache_chain *pos = NULL, *new;
+
+ list_for_each_entry(pos, list, head) {
+ int cmp = strcmp(pos->name, name);
+
+ if (!cmp)
+ return;
+ if (cmp > 0)
+ break;
+ }
+
+ new = xtables_malloc(sizeof(*new));
+ new->name = strdup(name);
+ list_add_tail(&new->head, pos ? &pos->head : list);
+}
+
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd)
+{
+ struct nft_cache_req *req = &h->cache_req;
+
+ if (level > req->level)
+ req->level = level;
+
+ if (!cmd || !cmd->table || req->all_chains)
+ return;
+
+ if (!req->table)
+ req->table = strdup(cmd->table);
+ else
+ assert(!strcmp(req->table, cmd->table));
+
+ if (!cmd->chain) {
+ req->all_chains = true;
+ return;
+ }
+
+ cache_chain_list_insert(&req->chain_list, cmd->chain);
+ if (cmd->rename)
+ cache_chain_list_insert(&req->chain_list, cmd->rename);
+ if (cmd->jumpto)
+ cache_chain_list_insert(&req->chain_list, cmd->jumpto);
+}
+
static int genid_cb(const struct nlmsghdr *nlh, void *data)
{
uint32_t *genid = data;
@@ -86,7 +133,7 @@ static int fetch_table_cache(struct nft_handle *h)
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_table_list *list;
- int ret;
+ int i, ret;
if (h->cache->tables)
return 0;
@@ -104,6 +151,21 @@ static int fetch_table_cache(struct nft_handle *h)
h->cache->tables = list;
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ h->cache->table[type].chains = nftnl_chain_list_alloc();
+ if (!h->cache->table[type].chains)
+ return 0;
+
+ h->cache->table[type].sets = nftnl_set_list_alloc();
+ if (!h->cache->table[type].sets)
+ return 0;
+ }
+
return 1;
}
@@ -239,40 +301,31 @@ static int fetch_set_cache(struct nft_handle *h,
.h = h,
.t = t,
};
+ uint16_t flags = NLM_F_DUMP;
+ struct nftnl_set *s = NULL;
struct nlmsghdr *nlh;
char buf[16536];
int i, ret;
- if (!t) {
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
+ if (t) {
+ s = nftnl_set_alloc();
+ if (!s)
+ return -1;
- if (!h->tables[i].name)
- continue;
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
- h->cache->table[type].sets = nftnl_set_list_alloc();
- if (!h->cache->table[type].sets)
- return -1;
+ if (set) {
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ flags = NLM_F_ACK;
}
- } else if (!h->cache->table[t->type].sets) {
- h->cache->table[t->type].sets = nftnl_set_list_alloc();
}
- if (t && set) {
- struct nftnl_set *s = nftnl_set_alloc();
-
- if (!s)
- return -1;
+ nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
+ h->family, flags, h->seq);
- nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
- NLM_F_ACK, h->seq);
- nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
- nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ if (s) {
nftnl_set_nlmsg_build_payload(nlh, s);
nftnl_set_free(s);
- } else {
- nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
- NLM_F_DUMP, h->seq);
}
ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
@@ -281,13 +334,7 @@ static int fetch_set_cache(struct nft_handle *h,
return ret;
}
- if (t && set) {
- struct nftnl_set *s;
-
- s = nftnl_set_list_lookup_byname(h->cache->table[t->type].sets,
- set);
- set_fetch_elem_cb(s, h);
- } else if (t) {
+ if (t) {
nftnl_set_list_foreach(h->cache->table[t->type].sets,
set_fetch_elem_cb, h);
} else {
@@ -304,9 +351,9 @@ static int fetch_set_cache(struct nft_handle *h,
return ret;
}
-static int fetch_chain_cache(struct nft_handle *h,
- const struct builtin_table *t,
- const char *chain)
+static int __fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ const struct nftnl_chain *c)
{
struct nftnl_chain_list_cb_data d = {
.h = h,
@@ -314,51 +361,47 @@ static int fetch_chain_cache(struct nft_handle *h,
};
char buf[16536];
struct nlmsghdr *nlh;
- int i, ret;
+ int ret;
- if (!t) {
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
+ c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
+ if (c)
+ nftnl_chain_nlmsg_build_payload(nlh, c);
- if (!h->tables[i].name)
- continue;
+ ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
- if (h->cache->table[type].chains)
- continue;
+ return ret;
+}
- h->cache->table[type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[type].chains)
- return -1;
- }
- } else if (!h->cache->table[t->type].chains) {
- h->cache->table[t->type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[t->type].chains)
- return -1;
- }
+static int fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ struct list_head *chains)
+{
+ struct cache_chain *cc;
+ struct nftnl_chain *c;
+ int rc, ret = 0;
- if (t && chain) {
- struct nftnl_chain *c = nftnl_chain_alloc();
+ if (!chains)
+ return __fetch_chain_cache(h, t, NULL);
- if (!c)
- return -1;
+ assert(t);
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
- h->family, NLM_F_ACK,
- h->seq);
- nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
- nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
- nftnl_chain_nlmsg_build_payload(nlh, c);
- nftnl_chain_free(c);
- } else {
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
- h->family, NLM_F_DUMP,
- h->seq);
- }
+ c = nftnl_chain_alloc();
+ if (!c)
+ return -1;
- ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
- if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
+
+ list_for_each_entry(cc, chains, head) {
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
+ rc = __fetch_chain_cache(h, t, c);
+ if (rc)
+ ret = rc;
+ }
+ nftnl_chain_free(c);
return ret;
}
@@ -417,20 +460,14 @@ static int nft_rule_list_update(struct nftnl_chain *c, void *data)
}
static int fetch_rule_cache(struct nft_handle *h,
- const struct builtin_table *t, const char *chain)
+ const struct builtin_table *t)
{
int i;
if (t) {
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
-
- list = h->cache->table[t->type].chains;
+ struct nftnl_chain_list *list =
+ h->cache->table[t->type].chains;
- if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
- return nft_rule_list_update(c, h);
- }
return nftnl_chain_list_foreach(list, nft_rule_list_update, h);
}
@@ -447,89 +484,46 @@ static int fetch_rule_cache(struct nft_handle *h,
return 0;
}
+static int flush_cache(struct nft_handle *h, struct nft_cache *c,
+ const char *tablename);
+
static void
-__nft_build_cache(struct nft_handle *h, enum nft_cache_level level,
- const struct builtin_table *t, const char *set,
- const char *chain)
+__nft_build_cache(struct nft_handle *h)
{
- uint32_t genid_start, genid_stop;
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ struct list_head *chains = NULL;
+ uint32_t genid_check;
- if (level <= h->cache_level)
+ if (h->cache_init)
return;
-retry:
- mnl_genid_get(h, &genid_start);
-
- if (h->cache_level && genid_start != h->nft_genid)
- flush_chain_cache(h, NULL);
-
- switch (h->cache_level) {
- case NFT_CL_NONE:
- fetch_table_cache(h);
- if (level == NFT_CL_TABLES)
- break;
- /* fall through */
- case NFT_CL_TABLES:
- fetch_chain_cache(h, t, chain);
- if (level == NFT_CL_CHAINS)
- break;
- /* fall through */
- case NFT_CL_CHAINS:
- fetch_set_cache(h, t, set);
- if (level == NFT_CL_SETS)
- break;
- /* fall through */
- case NFT_CL_SETS:
- fetch_rule_cache(h, t, chain);
- if (level == NFT_CL_RULES)
- break;
- /* fall through */
- case NFT_CL_RULES:
- break;
- }
- mnl_genid_get(h, &genid_stop);
- if (genid_start != genid_stop) {
- flush_chain_cache(h, NULL);
- goto retry;
+ if (req->table) {
+ t = nft_table_builtin_find(h, req->table);
+ if (!req->all_chains)
+ chains = &req->chain_list;
}
- if (!t && !chain)
- h->cache_level = level;
- else if (h->cache_level < NFT_CL_TABLES)
- h->cache_level = NFT_CL_TABLES;
-
- h->nft_genid = genid_start;
-}
-
-void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c)
-{
- const struct builtin_table *t;
- const char *table, *chain;
-
- if (!c)
- return __nft_build_cache(h, NFT_CL_RULES, NULL, NULL, NULL);
-
- table = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- t = nft_table_builtin_find(h, table);
- __nft_build_cache(h, NFT_CL_RULES, t, NULL, chain);
-}
-
-void nft_fake_cache(struct nft_handle *h)
-{
- int i;
-
- fetch_table_cache(h);
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
-
- if (!h->tables[i].name)
- continue;
+ h->cache_init = true;
+retry:
+ mnl_genid_get(h, &h->nft_genid);
- h->cache->table[type].chains = nftnl_chain_list_alloc();
+ if (req->level >= NFT_CL_TABLES)
+ fetch_table_cache(h);
+ if (req->level == NFT_CL_FAKE)
+ return;
+ if (req->level >= NFT_CL_CHAINS)
+ fetch_chain_cache(h, t, chains);
+ if (req->level >= NFT_CL_SETS)
+ fetch_set_cache(h, t, NULL);
+ if (req->level >= NFT_CL_RULES)
+ fetch_rule_cache(h, t);
+
+ mnl_genid_get(h, &genid_check);
+ if (h->nft_genid != genid_check) {
+ flush_cache(h, h->cache, NULL);
+ goto retry;
}
- h->cache_level = NFT_CL_RULES;
- mnl_genid_get(h, &h->nft_genid);
}
static void __nft_flush_cache(struct nft_handle *h)
@@ -610,51 +604,93 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (h->tables[i].name == NULL)
continue;
- if (!c->table[i].chains)
- continue;
-
- nftnl_chain_list_free(c->table[i].chains);
- c->table[i].chains = NULL;
- if (c->table[i].sets)
+ if (c->table[i].chains) {
+ nftnl_chain_list_free(c->table[i].chains);
+ c->table[i].chains = NULL;
+ }
+ if (c->table[i].sets) {
nftnl_set_list_free(c->table[i].sets);
- c->table[i].sets = NULL;
+ c->table[i].sets = NULL;
+ }
+ }
+ if (c->tables) {
+ nftnl_table_list_free(c->tables);
+ c->tables = NULL;
}
- nftnl_table_list_free(c->tables);
- c->tables = NULL;
return 1;
}
void flush_chain_cache(struct nft_handle *h, const char *tablename)
{
- if (!h->cache_level)
+ if (!h->cache_init)
return;
if (flush_cache(h, h->cache, tablename))
- h->cache_level = NFT_CL_NONE;
+ h->cache_init = false;
}
void nft_rebuild_cache(struct nft_handle *h)
{
- enum nft_cache_level level = h->cache_level;
-
- if (h->cache_level)
+ if (h->cache_init) {
__nft_flush_cache(h);
+ h->cache_init = false;
+ }
+
+ __nft_build_cache(h);
+}
+
+void nft_cache_build(struct nft_handle *h)
+{
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ int i;
+
+ if (req->table)
+ t = nft_table_builtin_find(h, req->table);
- h->cache_level = NFT_CL_NONE;
- __nft_build_cache(h, level, NULL, NULL, NULL);
+ /* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
+ * doesn't override policies by accident */
+ if (t && !req->all_chains) {
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ const char *cname = t->chains[i].name;
+
+ if (!cname)
+ break;
+ cache_chain_list_insert(&req->chain_list, cname);
+ }
+ }
+
+ __nft_build_cache(h);
}
void nft_release_cache(struct nft_handle *h)
{
- if (h->cache_index)
- flush_cache(h, &h->__cache[0], NULL);
+ struct nft_cache_req *req = &h->cache_req;
+ struct cache_chain *cc, *cc_tmp;
+
+ while (h->cache_index)
+ flush_cache(h, &h->__cache[h->cache_index--], NULL);
+ flush_cache(h, &h->__cache[0], NULL);
+ h->cache = &h->__cache[0];
+ h->cache_init = false;
+
+ if (req->level != NFT_CL_FAKE)
+ req->level = NFT_CL_TABLES;
+ if (req->table) {
+ free(req->table);
+ req->table = NULL;
+ }
+ req->all_chains = false;
+ list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
+ list_del(&cc->head);
+ free(cc->name);
+ free(cc);
+ }
}
struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
{
- __nft_build_cache(h, NFT_CL_TABLES, NULL, NULL, NULL);
-
return h->cache->tables;
}
@@ -667,8 +703,6 @@ nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
if (!t)
return NULL;
- __nft_build_cache(h, NFT_CL_RULES, t, set, NULL);
-
return h->cache->table[t->type].sets;
}
@@ -681,8 +715,6 @@ nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
if (!t)
return NULL;
- __nft_build_cache(h, NFT_CL_CHAINS, t, NULL, chain);
-
return h->cache->table[t->type].chains;
}
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index ed498835..f4291180 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -2,14 +2,16 @@
#define _NFT_CACHE_H_
struct nft_handle;
+struct nft_cmd;
-void nft_fake_cache(struct nft_handle *h);
-void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c);
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd);
void nft_rebuild_cache(struct nft_handle *h);
void nft_release_cache(struct nft_handle *h);
void flush_chain_cache(struct nft_handle *h, const char *tablename);
int flush_rule_cache(struct nft_handle *h, const char *table,
struct nftnl_chain *c);
+void nft_cache_build(struct nft_handle *h);
struct nftnl_chain_list *
nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
new file mode 100644
index 00000000..9c0901e7
--- /dev/null
+++ b/iptables/nft-cmd.c
@@ -0,0 +1,395 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "nft.h"
+#include "nft-cmd.h"
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nftnl_rule *rule;
+ struct nft_cmd *cmd;
+
+ cmd = calloc(1, sizeof(struct nft_cmd));
+ if (!cmd)
+ return NULL;
+
+ cmd->command = command;
+ cmd->table = strdup(table);
+ if (chain)
+ cmd->chain = strdup(chain);
+ cmd->rulenum = rulenum;
+ cmd->verbose = verbose;
+
+ if (state) {
+ rule = nft_rule_new(h, chain, table, state);
+ if (!rule)
+ return NULL;
+
+ cmd->obj.rule = rule;
+
+ if (!state->target && strlen(state->jumpto) > 0)
+ cmd->jumpto = strdup(state->jumpto);
+ }
+
+ list_add_tail(&cmd->head, &h->cmd_list);
+
+ return cmd;
+}
+
+void nft_cmd_free(struct nft_cmd *cmd)
+{
+ free((void *)cmd->table);
+ free((void *)cmd->chain);
+ free((void *)cmd->policy);
+ free((void *)cmd->rename);
+ free((void *)cmd->jumpto);
+
+ switch (cmd->command) {
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_RULE_DELETE:
+ if (cmd->obj.rule)
+ nftnl_rule_free(cmd->obj.rule);
+ break;
+ default:
+ break;
+ }
+
+ list_del(&cmd->head);
+ free(cmd);
+}
+
+static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, cmd->table);
+ if (!t)
+ return;
+
+ /* Since ebtables user-defined chain policies are implemented as last
+ * rule in nftables, rule cache is required here to treat them right.
+ */
+ if (h->family == NFPROTO_BRIDGE &&
+ !nft_chain_builtin_find(t, cmd->chain))
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+}
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ if (cmd->rulenum > 0)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, state,
+ -1, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, NULL,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_FLUSH, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ if (chain || verbose)
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_ZERO, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_ADD, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ /* This triggers nft_bridge_chain_postprocess() when fetching the
+ * rule cache.
+ */
+ if (h->family == NFPROTO_BRIDGE)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RENAME, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->rename = strdup(newname);
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_LIST, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->format = format;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_REPLACE, table, chain, data,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHECK, table, chain, data, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_UPDATE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+ if (counters)
+ cmd->counters = *counters;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_table_flush(struct nft_handle *h, const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RESTORE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_ZERO, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_SAVE, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->counters_save = counters;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, table, chain,
+ NULL, -1, false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+void nft_cmd_table_new(struct nft_handle *h, const char *table)
+{
+ nft_cmd_new(h, NFT_COMPAT_TABLE_NEW, table, NULL, NULL, -1, false);
+}
diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h
new file mode 100644
index 00000000..0e1776ce
--- /dev/null
+++ b/iptables/nft-cmd.h
@@ -0,0 +1,79 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+#include <libiptc/linux_list.h>
+#include <stdbool.h>
+#include "nft.h"
+
+struct nftnl_rule;
+
+struct nft_cmd {
+ struct list_head head;
+ int command;
+ const char *table;
+ const char *chain;
+ const char *jumpto;
+ int rulenum;
+ bool verbose;
+ unsigned int format;
+ struct {
+ struct nftnl_rule *rule;
+ struct nftnl_set *set;
+ } obj;
+ const char *policy;
+ struct xt_counters counters;
+ const char *rename;
+ int counters_save;
+};
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose);
+void nft_cmd_free(struct nft_cmd *cmd);
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose);
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose);
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose);
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose);
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format);
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose);
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters);
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname);
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose);
+int nft_cmd_table_flush(struct nft_handle *h, const char *table);
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum);
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters);
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy);
+void nft_cmd_table_new(struct nft_handle *h, const char *table);
+
+#endif /* _NFT_CMD_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 70634f8f..afdecf97 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -288,7 +288,7 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv4_addr(char letter, const struct in_addr *addr,
@@ -450,13 +450,11 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv4_proto_parse,
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv4_xlate,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index d01491bf..4008b7ea 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -217,7 +217,7 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv6_addr(char letter, const struct in6_addr *addr,
@@ -402,13 +402,11 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv6_proto_parse,
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv6_xlate,
};
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 42676564..c5a8f3fc 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -831,14 +831,6 @@ void save_rule_details(const struct iptables_command_state *cs,
}
}
-void save_counters(const void *data)
-{
- const struct iptables_command_state *cs = data;
-
- printf("[%llu:%llu] ", (unsigned long long)cs->counters.pcnt,
- (unsigned long long)cs->counters.bcnt);
-}
-
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -989,41 +981,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data)
cs->target = t;
}
-bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r, void *data)
-{
- struct iptables_command_state *cs = data, this = {};
- bool ret = false;
-
- nft_rule_to_iptables_command_state(h, r, &this);
-
- DEBUGP("comparing with... ");
-#ifdef DEBUG_DEL
- nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
-#endif
- if (!h->ops->is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
void nft_check_xt_legacy(int family, bool is_ipt_save)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index bee99a7d..94437ffe 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -98,7 +98,6 @@ struct nft_family_ops {
void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format);
void (*save_rule)(const void *data, unsigned int format);
- void (*save_counters)(const void *data);
void (*save_chain)(const struct nftnl_chain *c, const char *policy);
void (*proto_parse)(struct iptables_command_state *cs,
struct xtables_args *args);
@@ -109,8 +108,6 @@ struct nft_family_ops {
void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
struct iptables_command_state *cs);
void (*clear_cs)(struct iptables_command_state *cs);
- bool (*rule_find)(struct nft_handle *h, struct nftnl_rule *r,
- void *data);
int (*xlate)(const void *data, struct xt_xlate *xl);
};
@@ -162,7 +159,6 @@ void save_rule_details(const struct iptables_command_state *cs,
unsigned const char *iniface_mask,
const char *outiface,
unsigned const char *outiface_mask);
-void save_counters(const void *data);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
@@ -171,8 +167,6 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family);
void nft_ipv46_parse_target(struct xtables_target *t, void *data);
-bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
diff --git a/iptables/nft.c b/iptables/nft.c
index 806b77fe..0c5a74fc 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -256,24 +256,6 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds)
return err;
}
-enum obj_update_type {
- NFT_COMPAT_TABLE_ADD,
- NFT_COMPAT_TABLE_FLUSH,
- NFT_COMPAT_CHAIN_ADD,
- NFT_COMPAT_CHAIN_USER_ADD,
- NFT_COMPAT_CHAIN_USER_DEL,
- NFT_COMPAT_CHAIN_USER_FLUSH,
- NFT_COMPAT_CHAIN_UPDATE,
- NFT_COMPAT_CHAIN_RENAME,
- NFT_COMPAT_CHAIN_ZERO,
- NFT_COMPAT_RULE_APPEND,
- NFT_COMPAT_RULE_INSERT,
- NFT_COMPAT_RULE_REPLACE,
- NFT_COMPAT_RULE_DELETE,
- NFT_COMPAT_RULE_FLUSH,
- NFT_COMPAT_SET_ADD,
-};
-
enum obj_action {
NFT_COMPAT_COMMIT,
NFT_COMPAT_ABORT,
@@ -362,6 +344,15 @@ static int mnl_append_error(const struct nft_handle *h,
snprintf(tcr, sizeof(tcr), "set %s",
nftnl_set_get_str(o->set, NFTNL_SET_NAME));
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
+ break;
}
return snprintf(buf, len, "%s: %s", errmsg, tcr);
@@ -411,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, r);
}
+static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
+
+static void batch_chain_flush(struct nft_handle *h,
+ const char *table, const char *chain)
+{
+ struct obj_update *obj, *tmp;
+
+ list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
+ struct nftnl_rule *r = obj->ptr;
+
+ switch (obj->type) {
+ case NFT_COMPAT_RULE_APPEND:
+ case NFT_COMPAT_RULE_INSERT:
+ case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_DELETE:
+ break;
+ default:
+ continue;
+ }
+
+ if (table &&
+ strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
+ continue;
+
+ if (chain &&
+ strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
+ continue;
+
+ batch_obj_del(h, obj);
+ }
+}
+
const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = {
.name = "raw",
@@ -746,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{
const struct builtin_table *t;
+ if (!h->cache_init)
+ return 0;
+
t = nft_table_builtin_find(h, table);
if (t == NULL)
return -1;
@@ -756,6 +782,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
if (nft_table_builtin_add(h, t) < 0)
return -1;
+ if (h->cache_req.level < NFT_CL_CHAINS)
+ return 0;
+
nft_chain_builtin_init(h, t);
h->cache->table[t->type].initialized = true;
@@ -789,8 +818,10 @@ int nft_restart(struct nft_handle *h)
return 0;
}
-int nft_init(struct nft_handle *h, const struct builtin_table *t)
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
{
+ memset(h, 0, sizeof(*h));
+
h->nl = mnl_socket_open(NETLINK_NETFILTER);
if (h->nl == NULL)
return -1;
@@ -800,19 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
return -1;
}
+ h->ops = nft_family_ops_lookup(family);
+ if (!h->ops)
+ xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
h->portid = mnl_socket_get_portid(h->nl);
h->tables = t;
h->cache = &h->__cache[0];
+ h->family = family;
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
+ INIT_LIST_HEAD(&h->cmd_list);
+ INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0;
}
void nft_fini(struct nft_handle *h)
{
- flush_chain_cache(h, NULL);
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &h->cmd_list)
+ nft_cmd_free(list_entry(pos, struct nft_cmd, head));
+
+ list_for_each_safe(pos, n, &h->obj_list)
+ batch_obj_del(h, list_entry(pos, struct obj_update, head));
+
+ list_for_each_safe(pos, n, &h->err_list)
+ mnl_err_list_free(list_entry(pos, struct mnl_err, head));
+
+ nft_release_cache(h);
mnl_socket_close(h->nl);
}
@@ -950,6 +999,7 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
{
static uint32_t set_id = 0;
struct nftnl_set *s;
+ struct nft_cmd *cmd;
s = nftnl_set_alloc();
if (!s)
@@ -965,7 +1015,14 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
- return batch_set_add(h, NFT_COMPAT_SET_ADD, s) ? s : NULL;
+ cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
+ if (!cmd) {
+ nftnl_set_free(s);
+ return NULL;
+ }
+ cmd->obj.set = s;
+
+ return s;
}
static struct nftnl_expr *
@@ -1320,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
inv ? NFT_RULE_COMPAT_F_INV : 0);
}
-static struct nftnl_rule *
+struct nftnl_rule *
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
void *data)
{
@@ -1348,28 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
- void *data, struct nftnl_rule *ref, bool verbose)
+ struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{
struct nftnl_chain *c;
- struct nftnl_rule *r;
int type;
nft_xt_builtin_init(h, table);
- /* Since ebtables user-defined chain policies are implemented as last
- * rule in nftables, rule cache is required here to treat them right. */
- if (h->family == NFPROTO_BRIDGE) {
- c = nft_chain_find(h, table, chain);
- if (c && !nft_chain_builtin(c))
- nft_build_cache(h, c);
- }
-
nft_fn = nft_rule_append;
- r = nft_rule_new(h, chain, table, data);
- if (r == NULL)
- return 0;
-
if (ref) {
nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
@@ -1377,17 +1421,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
} else
type = NFT_COMPAT_RULE_APPEND;
- if (batch_rule_add(h, type, r) == NULL) {
- nftnl_rule_free(r);
+ if (batch_rule_add(h, type, r) == NULL)
return 0;
- }
if (verbose)
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
if (ref) {
nftnl_chain_rule_insert_at(r, ref);
- nftnl_chain_rule_del(r);
+ nftnl_chain_rule_del(ref);
+ nftnl_rule_free(ref);
} else {
c = nft_chain_find(h, table, chain);
if (!c) {
@@ -1410,8 +1453,9 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
ops->rule_to_cs(h, r, &cs);
- if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
- ops->save_counters(&cs);
+ if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
+ printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
+ (unsigned long long)cs.counters.bcnt);
/* print chain name */
switch(type) {
@@ -1594,7 +1638,6 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
c = nftnl_chain_list_iter_next(iter);
while (c) {
- nft_build_cache(h, c);
ret = nft_chain_save_rules(h, c, format);
if (ret != 0)
break;
@@ -1608,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
return ret == 0 ? 1 : 0;
}
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id)
+{
+ struct obj_update *n;
+
+ list_for_each_entry(n, &h->obj_list, head) {
+ if (n->type == NFT_COMPAT_SET_ADD &&
+ nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
+ return n->set;
+ }
+
+ return NULL;
+}
+
static void
__nft_rule_flush(struct nft_handle *h, const char *table,
const char *chain, bool verbose, bool implicit)
@@ -1664,6 +1721,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
}
if (chain || !verbose) {
+ batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
return 1;
@@ -1679,6 +1737,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
while (c != NULL) {
chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
c = nftnl_chain_list_iter_next(iter);
@@ -1740,7 +1799,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
} else {
c = nftnl_chain_alloc();
if (!c)
- return -1;
+ return 0;
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
@@ -1751,7 +1810,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
if (!created)
- return 0;
+ return 1;
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
@@ -1759,7 +1818,8 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
if (list)
nftnl_chain_list_add(c, list);
- return ret;
+ /* the core expects 1 for success and 0 for error */
+ return ret == 0 ? 1 : 0;
}
/* From linux/netlink.h */
@@ -1787,10 +1847,6 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
- /* This triggers required policy rule deletion. */
- if (h->family == NFPROTO_BRIDGE)
- nft_build_cache(h, c);
-
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
@@ -2065,15 +2121,53 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
return 1;
}
+static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
+ struct nftnl_rule *rule)
+{
+ struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
+ bool ret = false;
+
+ h->ops->rule_to_cs(h, r, &this);
+ h->ops->rule_to_cs(h, rule, cs);
+
+ DEBUGP("comparing with... ");
+#ifdef DEBUG_DEL
+ nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
+#endif
+ if (!h->ops->is_same(cs, &this))
+ goto out;
+
+ if (!compare_matches(cs->matches, this.matches)) {
+ DEBUGP("Different matches\n");
+ goto out;
+ }
+
+ if (!compare_targets(cs->target, this.target)) {
+ DEBUGP("Different target\n");
+ goto out;
+ }
+
+ if ((!cs->target || !this.target) &&
+ strcmp(cs->jumpto, this.jumpto) != 0) {
+ DEBUGP("Different verdict\n");
+ goto out;
+ }
+
+ ret = true;
+out:
+ h->ops->clear_cs(&this);
+ h->ops->clear_cs(cs);
+ return ret;
+}
+
static struct nftnl_rule *
-nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
+nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
+ struct nftnl_rule *rule, int rulenum)
{
struct nftnl_rule *r;
struct nftnl_rule_iter *iter;
bool found = false;
- nft_build_cache(h, c);
-
if (rulenum >= 0)
/* Delete by rule number case */
return nftnl_rule_lookup_byindex(c, rulenum);
@@ -2084,7 +2178,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- found = h->ops->rule_find(h, r, data);
+ found = nft_rule_cmp(h, r, rule);
if (found)
break;
r = nftnl_rule_iter_next(iter);
@@ -2096,7 +2190,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
}
int nft_rule_check(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
struct nftnl_chain *c;
struct nftnl_rule *r;
@@ -2107,7 +2201,7 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if (!c)
goto fail_enoent;
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r == NULL)
goto fail_enoent;
@@ -2121,7 +2215,7 @@ fail_enoent:
}
int nft_rule_delete(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
int ret = 0;
struct nftnl_chain *c;
@@ -2135,7 +2229,7 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r != NULL) {
ret =__nft_rule_del(h, r);
if (ret < 0)
@@ -2150,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
static struct nftnl_rule *
nft_rule_add(struct nft_handle *h, const char *chain,
- const char *table, struct iptables_command_state *cs,
+ const char *table, struct nftnl_rule *r,
struct nftnl_rule *ref, bool verbose)
{
- struct nftnl_rule *r;
uint64_t ref_id;
- r = nft_rule_new(h, chain, table, cs);
- if (r == NULL)
- return NULL;
-
if (ref) {
ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
if (ref_id > 0) {
@@ -2176,10 +2265,8 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
}
- if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
- nftnl_rule_free(r);
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
return NULL;
- }
if (verbose)
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
@@ -2188,9 +2275,10 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
int nft_rule_insert(struct nft_handle *h, const char *chain,
- const char *table, void *data, int rulenum, bool verbose)
+ const char *table, struct nftnl_rule *new_rule, int rulenum,
+ bool verbose)
{
- struct nftnl_rule *r = NULL, *new_rule;
+ struct nftnl_rule *r = NULL;
struct nftnl_chain *c;
nft_xt_builtin_init(h, table);
@@ -2204,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
}
if (rulenum > 0) {
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, new_rule, rulenum);
if (r == NULL) {
/* special case: iptables allows to insert into
* rule_count + 1 position.
*/
- r = nft_rule_find(h, c, data, rulenum - 1);
+ r = nft_rule_find(h, c, new_rule, rulenum - 1);
if (r != NULL)
- return nft_rule_append(h, chain, table, data,
- NULL, verbose);
+ return nft_rule_append(h, chain, table,
+ new_rule, NULL, verbose);
errno = E2BIG;
goto err;
}
}
- new_rule = nft_rule_add(h, chain, table, data, r, verbose);
+ new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
if (!new_rule)
goto err;
@@ -2261,7 +2349,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
}
int nft_rule_replace(struct nft_handle *h, const char *chain,
- const char *table, void *data, int rulenum, bool verbose)
+ const char *table, struct nftnl_rule *rule,
+ int rulenum, bool verbose)
{
int ret = 0;
struct nftnl_chain *c;
@@ -2275,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, rule, rulenum);
if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
- ret = nft_rule_append(h, chain, table, data, r, verbose);
+ ret = nft_rule_append(h, chain, table, rule, r, verbose);
} else
errno = E2BIG;
@@ -2514,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum)
{
struct iptables_command_state cs = {};
+ struct nftnl_rule *r, *new_rule;
struct nftnl_chain *c;
- struct nftnl_rule *r;
int ret = 0;
nft_fn = nft_rule_delete;
@@ -2534,8 +2623,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
nft_rule_to_iptables_command_state(h, r, &cs);
cs.counters.pcnt = cs.counters.bcnt = 0;
+ new_rule = nft_rule_new(h, chain, table, &cs);
+ if (!new_rule)
+ return 1;
- ret = nft_rule_append(h, chain, table, &cs, r, false);
+ ret = nft_rule_append(h, chain, table, new_rule, r, false);
error:
return ret;
@@ -2629,14 +2721,23 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
- case NFT_COMPAT_RULE_DELETE:
break;
+ case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule);
break;
case NFT_COMPAT_SET_ADD:
nftnl_set_free(o->set);
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
+ break;
}
h->obj_list_num--;
list_del(&o->head);
@@ -2704,6 +2805,13 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
case NFT_COMPAT_SET_ADD:
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
break;
}
}
@@ -2801,6 +2909,14 @@ retry:
NLM_F_CREATE, &n->seq, n->set);
seq = n->seq;
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
}
mnl_nft_batch_continue(h->batch);
@@ -2821,7 +2937,6 @@ retry:
nft_refresh_transaction(h);
- i=0;
list_for_each_entry_safe(err, ne, &h->err_list, head)
mnl_err_list_free(err);
@@ -2896,27 +3011,33 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
+ ebt_cs_clean(&cs);
+
if (!r)
return -1;
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udata)
- return -1;
+ goto err_free_rule;
if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
- return -1;
+ goto err_free_rule;
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
nftnl_udata_buf_data(udata),
nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata);
- if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) {
- nftnl_rule_free(r);
- return -1;
- }
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
+ goto err_free_rule;
+
+ /* add the rule to chain so it is freed later */
+ nftnl_chain_rule_add_tail(r, c);
return 0;
+err_free_rule:
+ nftnl_rule_free(r);
+ return -1;
}
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
@@ -2937,8 +3058,6 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
else
return 0;
- nft_build_cache(h, c);
-
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
return 1;
}
@@ -2963,41 +3082,152 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
}
}
-int nft_commit(struct nft_handle *h)
+static void assert_chain_exists(struct nft_handle *h,
+ const char *table, const char *chain)
{
- return nft_action(h, NFT_COMPAT_COMMIT);
+ if (chain && !nft_chain_exists(h, table, chain))
+ xtables_error(PARAMETER_PROBLEM,
+ "Chain '%s' does not exist", chain);
}
-int nft_bridge_commit(struct nft_handle *h)
+static int nft_prepare(struct nft_handle *h)
{
- nft_bridge_commit_prepare(h);
- return nft_commit(h);
+ struct nft_cmd *cmd, *next;
+ int ret = 1;
+
+ nft_cache_build(h);
+
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
+ switch (cmd->command) {
+ case NFT_COMPAT_TABLE_FLUSH:
+ ret = nft_table_flush(h, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_ADD:
+ ret = nft_chain_user_add(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_DEL:
+ ret = nft_chain_user_del(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_CHAIN_RESTORE:
+ ret = nft_chain_restore(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_UPDATE:
+ ret = nft_chain_set(h, cmd->table, cmd->chain,
+ cmd->policy, &cmd->counters);
+ break;
+ case NFT_COMPAT_CHAIN_RENAME:
+ ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
+ cmd->rename);
+ break;
+ case NFT_COMPAT_CHAIN_ZERO:
+ ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_APPEND:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_append(h, cmd->chain, cmd->table,
+ cmd->obj.rule, NULL, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_INSERT:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_insert(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_REPLACE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_replace(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_DELETE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ if (cmd->rulenum >= 0)
+ ret = nft_rule_delete_num(h, cmd->chain,
+ cmd->table,
+ cmd->rulenum,
+ cmd->verbose);
+ else
+ ret = nft_rule_delete(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_FLUSH:
+ ret = nft_rule_flush(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_LIST:
+ ret = nft_rule_list(h, cmd->chain, cmd->table,
+ cmd->rulenum, cmd->format);
+ break;
+ case NFT_COMPAT_RULE_CHECK:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_check(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_ZERO:
+ ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
+ cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_SAVE:
+ ret = nft_rule_list_save(h, cmd->chain, cmd->table,
+ cmd->rulenum,
+ cmd->counters_save);
+ break;
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ ret = ebt_set_user_chain_policy(h, cmd->table,
+ cmd->chain, cmd->policy);
+ break;
+ case NFT_COMPAT_TABLE_NEW:
+ nft_xt_builtin_init(h, cmd->table);
+ ret = 1;
+ break;
+ case NFT_COMPAT_SET_ADD:
+ nft_xt_builtin_init(h, cmd->table);
+ batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
+ ret = 1;
+ break;
+ case NFT_COMPAT_TABLE_ADD:
+ case NFT_COMPAT_CHAIN_ADD:
+ assert(0);
+ break;
+ }
+
+ nft_cmd_free(cmd);
+
+ if (ret == 0)
+ return 0;
+ }
+
+ return 1;
}
-int nft_abort(struct nft_handle *h)
+int nft_commit(struct nft_handle *h)
{
- return nft_action(h, NFT_COMPAT_ABORT);
+ if (!nft_prepare(h))
+ return 0;
+
+ return nft_action(h, NFT_COMPAT_COMMIT);
}
-int nft_abort_policy_rule(struct nft_handle *h, const char *table)
+int nft_bridge_commit(struct nft_handle *h)
{
- struct obj_update *n, *tmp;
+ if (!nft_prepare(h))
+ return 0;
- list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
- if (n->type != NFT_COMPAT_RULE_APPEND &&
- n->type != NFT_COMPAT_RULE_DELETE)
- continue;
+ nft_bridge_commit_prepare(h);
- if (strcmp(table,
- nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
- continue;
+ return nft_action(h, NFT_COMPAT_COMMIT);
+}
- if (!nft_rule_is_policy_rule(n->rule))
- continue;
+int nft_abort(struct nft_handle *h)
+{
+ struct nft_cmd *cmd, *next;
- batch_obj_del(h, n);
- }
- return 0;
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
+ nft_cmd_free(cmd);
+
+ return nft_action(h, NFT_COMPAT_ABORT);
}
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
@@ -3180,8 +3410,6 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
return -1;
}
- nft_build_cache(h, c);
-
iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return -1;
@@ -3318,8 +3546,6 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
enum nf_inet_hooks hook;
int prio;
- nft_build_cache(h, c);
-
if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
return -1;
diff --git a/iptables/nft.h b/iptables/nft.h
index 51b56603..bd783231 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -3,6 +3,8 @@
#include "xshared.h"
#include "nft-shared.h"
+#include "nft-cache.h"
+#include "nft-cmd.h"
#include <libiptc/linux_list.h>
enum nft_table_type {
@@ -28,11 +30,11 @@ struct builtin_table {
};
enum nft_cache_level {
- NFT_CL_NONE,
NFT_CL_TABLES,
NFT_CL_CHAINS,
NFT_CL_SETS,
- NFT_CL_RULES
+ NFT_CL_RULES,
+ NFT_CL_FAKE /* must be last entry */
};
struct nft_cache {
@@ -44,6 +46,43 @@ struct nft_cache {
} table[NFT_TABLE_MAX];
};
+enum obj_update_type {
+ NFT_COMPAT_TABLE_ADD,
+ NFT_COMPAT_TABLE_FLUSH,
+ NFT_COMPAT_CHAIN_ADD,
+ NFT_COMPAT_CHAIN_USER_ADD,
+ NFT_COMPAT_CHAIN_USER_DEL,
+ NFT_COMPAT_CHAIN_USER_FLUSH,
+ NFT_COMPAT_CHAIN_UPDATE,
+ NFT_COMPAT_CHAIN_RENAME,
+ NFT_COMPAT_CHAIN_ZERO,
+ NFT_COMPAT_RULE_APPEND,
+ NFT_COMPAT_RULE_INSERT,
+ NFT_COMPAT_RULE_REPLACE,
+ NFT_COMPAT_RULE_DELETE,
+ NFT_COMPAT_RULE_FLUSH,
+ NFT_COMPAT_SET_ADD,
+ NFT_COMPAT_RULE_LIST,
+ NFT_COMPAT_RULE_CHECK,
+ NFT_COMPAT_CHAIN_RESTORE,
+ NFT_COMPAT_RULE_SAVE,
+ NFT_COMPAT_RULE_ZERO,
+ NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE,
+ NFT_COMPAT_TABLE_NEW,
+};
+
+struct cache_chain {
+ struct list_head head;
+ char *name;
+};
+
+struct nft_cache_req {
+ enum nft_cache_level level;
+ char *table;
+ bool all_chains;
+ struct list_head chain_list;
+};
+
struct nft_handle {
int family;
struct mnl_socket *nl;
@@ -62,10 +101,12 @@ struct nft_handle {
unsigned int cache_index;
struct nft_cache __cache[2];
struct nft_cache *cache;
- enum nft_cache_level cache_level;
+ struct nft_cache_req cache_req;
bool restore;
bool noflush;
int8_t config_done;
+ struct list_head cmd_list;
+ bool cache_init;
/* meta data, for error reporting */
struct {
@@ -80,7 +121,7 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data);
-int nft_init(struct nft_handle *h, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
void nft_fini(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
@@ -116,16 +157,23 @@ void nft_bridge_chain_postprocess(struct nft_handle *h,
/*
+ * Operations with sets.
+ */
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id);
+
+/*
* Operations with rule-set.
*/
struct nftnl_rule;
-int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, struct nftnl_rule *ref, bool verbose);
-int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
-int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
-int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
+int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
+int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
+int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
+int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose);
-int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
+int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format);
int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters);
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format);
@@ -159,7 +207,6 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
int nft_commit(struct nft_handle *h);
int nft_bridge_commit(struct nft_handle *h);
int nft_abort(struct nft_handle *h);
-int nft_abort_policy_rule(struct nft_handle *h, const char *table);
/*
* revision compatibility.
@@ -178,6 +225,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname);
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h, const char *pname);
+void nft_fini_eb(struct nft_handle *h);
int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index d71c1372..2125e2cb 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -46,6 +46,10 @@ while [ -n "$1" ]; do
NFT_ONLY=y
shift
;;
+ -V|--valgrind)
+ VALGRIND=y
+ shift
+ ;;
*${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1"
VERBOSE=y
@@ -67,6 +71,49 @@ else
XTABLES_LEGACY_MULTI="xtables-legacy-multi"
fi
+printscript() { # (cmd, tmpd)
+ cat <<EOF
+#!/bin/bash
+
+CMD="$1"
+
+# note: valgrind man page warns about --log-file with --trace-children, the
+# last child executed overwrites previous reports unless %p or %q is used.
+# Since libtool wrapper calls exec but none of the iptables tools do, this is
+# perfect for us as it effectively hides bash-related errors
+
+valgrind --log-file=$2/valgrind.log --trace-children=yes \
+ --leak-check=full --show-leak-kinds=all \$CMD "\$@"
+RC=\$?
+
+# don't keep uninteresting logs
+if grep -q 'no leaks are possible' $2/valgrind.log; then
+ rm $2/valgrind.log
+else
+ mv $2/valgrind.log $2/valgrind_\$\$.log
+fi
+
+# drop logs for failing commands for now
+[ \$RC -eq 0 ] || rm $2/valgrind_\$\$.log
+
+exit \$RC
+EOF
+}
+
+if [ "$VALGRIND" == "y" ]; then
+ tmpd=$(mktemp -d)
+ msg_info "writing valgrind logs to $tmpd"
+ chmod a+rx $tmpd
+ printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi
+ printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi
+ trap "rm ${tmpd}/xtables-*-multi" EXIT
+ chmod a+x ${tmpd}/xtables-nft-multi ${tmpd}/xtables-legacy-multi
+
+ XTABLES_NFT_MULTI="${tmpd}/xtables-nft-multi"
+ XTABLES_LEGACY_MULTI="${tmpd}/xtables-legacy-multi"
+
+fi
+
find_tests() {
if [ ! -z "$SINGLE" ] ; then
echo $SINGLE
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
index f023b791..c583b0eb 100755
--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
@@ -26,6 +26,7 @@ cmd 1 ip6tables -N foo
# test rule adding
cmd 0 ip6tables -A INPUT -j ACCEPT
cmd 1 ip6tables -A noexist -j ACCEPT
+cmd 2 ip6tables -I INPUT -j foobar
# test rule checking
cmd 0 ip6tables -C INPUT -j ACCEPT
diff --git a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
index ce3bef3a..3f443a98 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
@@ -22,7 +22,7 @@ do_simple()
table="${2}"
dumpfile="$(dirname "${0}")/dumps/${iptables}.dump"
- "$XT_MULTI" "${iptables}-restore" --table="${table}" <"${dumpfile}"; rv=$?
+ "$XT_MULTI" "${iptables}-restore" --table="${table}" "${dumpfile}"; rv=$?
if [ "${rv}" -ne 0 ]; then
RET=1
diff --git a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0 b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
index 9fc50615..a7fae41d 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
@@ -45,8 +45,7 @@ get_target()
make_dummy_rules()
{
-
- echo "*filter"
+ echo "*${1:-filter}"
echo ":INPUT ACCEPT [0:0]"
echo ":FORWARD ACCEPT [0:0]"
echo ":OUTPUT ACCEPT [0:0]"
@@ -74,7 +73,7 @@ make_dummy_rules()
tmpfile=$(mktemp) || exit 1
dumpfile=$(mktemp) || exit 1
-make_dummy_rules > $dumpfile
+(make_dummy_rules; make_dummy_rules security) > $dumpfile
$XT_MULTI iptables-restore -w < $dumpfile
LINES1=$(wc -l < $dumpfile)
$XT_MULTI iptables-save | grep -v '^#' > $dumpfile
diff --git a/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0 b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
index 739e684a..2817376e 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
@@ -8,3 +8,4 @@ $XT_MULTI iptables-restore --noflush <<EOF
:foobar - [0:0]
-A foobar -j ACCEPT
COMMIT
+EOF
diff --git a/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0 b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
new file mode 100755
index 00000000..fd82afa1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# make sure -F lines don't cause segfaults
+
+RULESET='*nat
+-F PREROUTING
+-A PREROUTING -j ACCEPT
+-F PREROUTING
+COMMIT'
+
+echo -e "$RULESET" | $XT_MULTI iptables-restore
+echo -e "$RULESET" | $XT_MULTI iptables-restore -n
diff --git a/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0 b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
new file mode 100755
index 00000000..65c3b9a1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -e
+
+# segfault with --test reported in nfbz#1391
+
+printf '%s\nCOMMIT\n' '*nat' '*raw' '*filter' | $XT_MULTI iptables-restore --test
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index ce02e0bc..f730bede 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -54,10 +54,16 @@ cmd 1 "$ENOENT" iptables -Z bar
# test chain rename
cmd 0 iptables -E foo bar
cmd 1 "$EEXIST_F" iptables -E foo bar
+cmd 1 "$ENOENT" iptables -E foo bar2
+cmd 0 iptables -N foo2
+cmd 1 "$EEXIST_F" iptables -E foo2 bar
# test rule adding
cmd 0 iptables -A INPUT -j ACCEPT
cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
+cmd 2 "" iptables -I INPUT -j foobar
+cmd 2 "" iptables -R INPUT 1 -j foobar
+cmd 2 "" iptables -D INPUT -j foobar
# test rulenum commands
cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT
diff --git a/iptables/tests/shell/testcases/iptables/0006-46-args_0 b/iptables/tests/shell/testcases/iptables/0006-46-args_0
new file mode 100755
index 00000000..17a0a018
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0006-46-args_0
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+RC=0
+
+$XT_MULTI iptables -6 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'iptables -6' returned $rc instead of 2"
+ RC=1
+fi
+
+$XT_MULTI ip6tables -4 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'ip6tables -4' returned $rc instead of 2"
+ RC=1
+fi
+
+RULESET='*filter
+-4 -A FORWARD -d 10.0.0.1 -j ACCEPT
+-6 -A FORWARD -d fec0:10::1 -j ACCEPT
+COMMIT
+'
+EXPECT4='-P FORWARD ACCEPT
+-A FORWARD -d 10.0.0.1/32 -j ACCEPT'
+EXPECT6='-P FORWARD ACCEPT
+-A FORWARD -d fec0:10::1/128 -j ACCEPT'
+EXPECT_EMPTY='-P FORWARD ACCEPT'
+
+echo "$RULESET" | $XT_MULTI iptables-restore || {
+ echo "iptables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+echo "$RULESET" | $XT_MULTI ip6tables-restore || {
+ echo "ip6tables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+$XT_MULTI ip6tables -F FORWARD
+
+$XT_MULTI iptables -4 -A FORWARD -d 10.0.0.1 -j ACCEPT || {
+ echo "iptables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+$XT_MULTI ip6tables -6 -A FORWARD -d fec0:10::1 -j ACCEPT || {
+ echo "ip6tables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+exit $RC
diff --git a/iptables/tests/shell/testcases/nft-only/0006-policy-override_0 b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
new file mode 100755
index 00000000..68e2019b
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+# make sure none of the commands invoking nft_xt_builtin_init() override
+# non-default chain policies via needless chain add.
+
+RC=0
+
+do_test() {
+ $XT_MULTI $@
+ $XT_MULTI iptables -S | grep -q -- '-P FORWARD DROP' && return
+
+ echo "command '$@' kills chain policies"
+ $XT_MULTI iptables -P FORWARD DROP
+ RC=1
+}
+
+$XT_MULTI iptables -P FORWARD DROP
+
+do_test iptables -A OUTPUT -j ACCEPT
+do_test iptables -F
+do_test iptables -N foo
+do_test iptables -E foo foo2
+do_test iptables -I OUTPUT -j ACCEPT
+do_test iptables -nL
+do_test iptables -S
+
+exit $RC
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 16c58914..c1d1371a 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -495,7 +495,6 @@ void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
continue;
} else if (*curchar == '"') {
quote_open = 0;
- *curchar = '"';
} else {
add_param(&param, curchar);
continue;
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 490b19ad..c41bd054 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <netinet/in.h>
#include <net/if.h>
+#include <sys/time.h>
#include <linux/netfilter_arp/arp_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
index eca7bb97..04cf7dcc 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -56,6 +56,7 @@ int xtables_arp_main(int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret)
fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 9cfad762..8632774d 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -235,7 +235,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(void)
+printhelp(void)
{
struct xtables_target *t = NULL;
int i;
@@ -325,7 +325,6 @@ exit_printhelp(void)
printf("\n");
t->help();
}
- exit(0);
}
static char
@@ -400,7 +399,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -427,10 +426,10 @@ append_entry(struct nft_handle *h,
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table, cs, NULL,
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table, cs,
+ ret = nft_cmd_rule_insert(h, chain, table, cs,
rulenum, verbose);
}
}
@@ -455,7 +454,7 @@ replace_entry(const char *chain,
cs->arp.arp.smsk.s_addr = smask->s_addr;
cs->arp.arp.tmsk.s_addr = dmask->s_addr;
- return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -479,7 +478,7 @@ delete_entry(const char *chain,
for (j = 0; j < ndaddrs; j++) {
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -500,17 +499,10 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
init_extensionsa();
#endif
- memset(h, 0, sizeof(*h));
- h->family = NFPROTO_ARP;
-
- if (nft_init(h, xtables_arp) < 0)
+ if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
return 0;
}
@@ -673,7 +665,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (!optarg)
optarg = argv[optind];
- exit_printhelp();
+ printhelp();
+ command = CMD_NONE;
break;
case 's':
check_inverse(optarg, &invert, &optind, argc);
@@ -888,8 +881,6 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (optind < argc)
xtables_error(PARAMETER_PROBLEM,
"unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
if (invert)
xtables_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
@@ -962,7 +953,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
+ ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
break;
case CMD_REPLACE:
ret = replace_entry(chain, *table, &cs, rulenum - 1,
@@ -984,10 +975,10 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_LINENUMBERS);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, chain, *table, options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_LIST|CMD_ZERO:
@@ -997,25 +988,27 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
/*options&OPT_EXPANDED*/0,
options&OPT_LINENUMBERS);
if (ret)
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, chain, *table,
+ ret = nft_cmd_chain_user_del(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, chain, *table, newname);
+ ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
policy);
break;
+ case CMD_NONE:
+ break;
default:
/* We should never reach this... */
exit_tryhelp(2);
@@ -1026,9 +1019,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
free(daddrs);
free(dmasks);
- if (cs.target)
- free(cs.target->t);
-
+ nft_clear_iptables_command_state(&cs);
xtables_free_opts(1);
/* if (verbose > 1)
diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c
index a9081c78..181cf2d0 100644
--- a/iptables/xtables-eb-standalone.c
+++ b/iptables/xtables-eb-standalone.c
@@ -53,6 +53,8 @@ int xtables_eb_main(int argc, char *argv[])
if (ret)
ret = nft_bridge_commit(&h);
+ nft_fini_eb(&h);
+
if (!ret)
fprintf(stderr, "ebtables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 15b971da..375a95d1 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -150,9 +150,9 @@ append_entry(struct nft_handle *h,
int ret = 1;
if (append)
- ret = nft_rule_append(h, chain, table, cs, NULL, verbose);
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL, verbose);
else
- ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose);
+ ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose);
return ret;
}
@@ -169,10 +169,10 @@ delete_entry(struct nft_handle *h,
int ret = 1;
if (rule_nr == -1)
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
else {
do {
- ret = nft_rule_delete_num(h, chain, table,
+ ret = nft_cmd_rule_delete_num(h, chain, table,
rule_nr, verbose);
rule_nr++;
} while (rule_nr < rule_nr_end);
@@ -427,7 +427,7 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table
if (!counters)
format |= FMT_NOCOUNTS;
- return nft_rule_list(h, chain, table, rule_nr, format);
+ return nft_cmd_rule_list(h, chain, table, rule_nr, format);
}
static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
@@ -739,16 +739,9 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
init_extensionsb();
#endif
- memset(h, 0, sizeof(*h));
-
- h->family = NFPROTO_BRIDGE;
-
- if (nft_init(h, xtables_bridge) < 0)
+ if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (!h->ops)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
/* manually registering ebt matches, given the original ebtables parser
* don't use '-m matchname' and the match can't be loaded dynamically when
@@ -759,6 +752,24 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
return 0;
}
+void nft_fini_eb(struct nft_handle *h)
+{
+ struct xtables_match *match;
+ struct xtables_target *target;
+
+ for (match = xtables_matches; match; match = match->next) {
+ free(match->m);
+ }
+ for (target = xtables_targets; target; target = target->next) {
+ free(target->t);
+ }
+
+ free(opts);
+
+ nft_fini(h);
+ xtables_fini();
+}
+
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
@@ -820,7 +831,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
flags |= OPT_COMMAND;
if (c == 'N') {
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
} else if (c == 'X') {
/* X arg is optional, optarg is NULL */
@@ -828,7 +839,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
chain = argv[optind];
optind++;
}
- ret = nft_chain_user_del(h, chain, *table, 0);
+ ret = nft_cmd_chain_user_del(h, chain, *table, 0);
break;
}
@@ -842,7 +853,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
- ret = nft_chain_user_rename(h, chain, *table,
+ ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]);
if (ret != 0 && errno == ENOENT)
xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
@@ -1144,7 +1155,7 @@ print_zero:
/*case 7 :*/ /* atomic-init */
/*case 10:*/ /* atomic-save */
case 11: /* init-table */
- nft_table_flush(h, *table);
+ nft_cmd_table_flush(h, *table);
return 1;
/*
replace->command = c;
@@ -1207,7 +1218,7 @@ print_zero:
if (command == 'h' && !(flags & OPT_ZERO)) {
print_help(cs.target, cs.matches, *table);
- exit(0);
+ ret = 1;
}
/* Do the final checks */
@@ -1232,13 +1243,13 @@ print_zero:
if (command == 'P') {
if (selected_chain >= NF_BR_NUMHOOKS) {
- ret = ebt_set_user_chain_policy(h, *table, chain, policy);
+ ret = ebt_cmd_user_chain_policy(h, *table, chain, policy);
} else {
if (strcmp(policy, "RETURN") == 0) {
xtables_error(PARAMETER_PROBLEM,
"Policy RETURN only allowed for user defined chains");
}
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy");
}
@@ -1251,9 +1262,9 @@ print_zero:
flags&LIST_C);
}
if (flags & OPT_ZERO) {
- ret = nft_chain_zero_counters(h, chain, *table, 0);
+ ret = nft_cmd_chain_zero_counters(h, chain, *table, 0);
} else if (command == 'F') {
- ret = nft_rule_flush(h, chain, *table, 0);
+ ret = nft_cmd_rule_flush(h, chain, *table, 0);
} else if (command == 'A') {
ret = append_entry(h, chain, *table, &cs, 0, 0, true);
} else if (command == 'I') {
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index a5245d14..57def83e 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -615,7 +615,7 @@ int xtables_monitor_main(int argc, char *argv[])
init_extensions4();
#endif
- if (nft_init(&h, xtables_ipv4)) {
+ if (nft_init(&h, AF_INET, xtables_ipv4)) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -688,6 +688,8 @@ int xtables_monitor_main(int argc, char *argv[])
}
mnl_socket_close(nl);
+ xtables_fini();
+
return EXIT_SUCCESS;
}
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index fb2ac8b5..a3bb4f00 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -61,11 +61,11 @@ static void print_usage(const char *name, const char *version)
static const struct nft_xt_restore_cb restore_cb = {
.commit = nft_commit,
.abort = nft_abort,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandx,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
struct nft_xt_restore_state {
@@ -85,8 +85,10 @@ static void xtables_restore_parse_line(struct nft_handle *h,
if (buffer[0] == '\n')
return;
else if (buffer[0] == '#') {
- if (verbose)
+ if (verbose) {
fputs(buffer, stdout);
+ fflush(stdout);
+ }
return;
} else if (state->in_table &&
(strncmp(buffer, "COMMIT", 6) == 0) &&
@@ -126,6 +128,10 @@ static void xtables_restore_parse_line(struct nft_handle *h,
if (p->tablename && (strcmp(p->tablename, table) != 0))
return;
+ /* implicit commit if no explicit COMMIT supported */
+ if (!p->commit)
+ cb->commit(h);
+
if (h->noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n", table);
if (cb->table_flush)
@@ -189,7 +195,7 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"cannot create chain '%s' (%s)\n",
chain, strerror(errno));
} else if (h->family == NFPROTO_BRIDGE &&
- !ebt_set_user_chain_policy(h, state->curtable->name,
+ !ebt_cmd_user_chain_policy(h, state->curtable->name,
chain, policy)) {
xtables_error(OTHER_PROBLEM,
"Can't set policy `%s' on `%s' line %u: %s\n",
@@ -248,99 +254,16 @@ static void xtables_restore_parse_line(struct nft_handle *h,
}
}
-/* Return true if given iptables-restore line will require a full cache.
- * Typically these are commands referring to an existing rule
- * (either by number or content) or commands listing the ruleset. */
-static bool cmd_needs_full_cache(char *cmd)
-{
- char c, chain[32];
- int rulenum, mcount;
-
- mcount = sscanf(cmd, "-%c %31s %d", &c, chain, &rulenum);
-
- if (mcount == 3)
- return true;
- if (mcount < 1)
- return false;
-
- switch (c) {
- case 'D':
- case 'C':
- case 'S':
- case 'L':
- case 'Z':
- return true;
- }
-
- return false;
-}
-
-#define PREBUFSIZ 65536
-
void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p)
{
struct nft_xt_restore_state state = {};
- char preload_buffer[PREBUFSIZ] = {}, buffer[10240] = {}, *ptr;
-
- if (!h->noflush) {
- nft_fake_cache(h);
- } else {
- ssize_t pblen = sizeof(preload_buffer);
- bool do_cache = false;
-
- ptr = preload_buffer;
- while (fgets(buffer, sizeof(buffer), p->in)) {
- size_t blen = strlen(buffer);
-
- /* Drop trailing newline; xtables_restore_parse_line()
- * uses strtok() which replaces them by nul-characters,
- * causing unpredictable string delimiting in
- * preload_buffer.
- * Unless this is an empty line which would fold into a
- * spurious EoB indicator (double nul-char). */
- if (buffer[blen - 1] == '\n' && blen > 1)
- buffer[blen - 1] = '\0';
- else
- blen++;
-
- pblen -= blen;
- if (pblen <= 0) {
- /* buffer exhausted */
- do_cache = true;
- break;
- }
-
- if (cmd_needs_full_cache(buffer)) {
- do_cache = true;
- break;
- }
-
- /* copy string including terminating nul-char */
- memcpy(ptr, buffer, blen);
- ptr += blen;
- buffer[0] = '\0';
- }
+ char buffer[10240] = {};
- if (do_cache)
- nft_build_cache(h, NULL);
- }
+ if (!h->noflush)
+ nft_cache_level_set(h, NFT_CL_FAKE, NULL);
line = 0;
- ptr = preload_buffer;
- while (*ptr) {
- size_t len = strlen(ptr);
-
- h->error.lineno = ++line;
- DEBUGP("%s: buffered line %d: '%s'\n", __func__, line, ptr);
- xtables_restore_parse_line(h, p, &state, ptr);
- ptr += len + 1;
- }
- if (*buffer) {
- h->error.lineno = ++line;
- DEBUGP("%s: overrun line %d: '%s'\n", __func__, line, buffer);
- xtables_restore_parse_line(h, p, &state, buffer);
- }
while (fgets(buffer, sizeof(buffer), p->in)) {
h->error.lineno = ++line;
DEBUGP("%s: input line %d: '%s'\n", __func__, line, buffer);
@@ -360,15 +283,13 @@ static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
const struct builtin_table *tables;
- struct nft_handle h = {
- .family = family,
- .restore = true,
- };
- int c;
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
};
+ bool noflush = false;
+ struct nft_handle h;
+ int c;
line = 0;
@@ -381,7 +302,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
exit(1);
}
- while ((c = getopt_long(argc, argv, "bcvVthnM:T:46wW", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) {
switch (c) {
case 'b':
fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -402,7 +323,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
print_usage(prog_name, PACKAGE_VERSION);
exit(0);
case 'n':
- h.noflush = 1;
+ noflush = true;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -410,13 +331,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
case 'T':
p.tablename = optarg;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'w': /* fallthrough. Ignored by xt-restore */
case 'W':
if (!optarg && xs_has_arg(argc, argv))
@@ -464,17 +378,20 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
exit(EXIT_FAILURE);
}
+ h.noflush = noflush;
+ h.restore = true;
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
return 0;
}
@@ -491,20 +408,13 @@ int xtables_ip6_restore_main(int argc, char *argv[])
argc, argv);
}
-static int ebt_table_flush(struct nft_handle *h, const char *table)
-{
- /* drop any pending policy rule add/removal jobs */
- nft_abort_policy_rule(h, table);
- return nft_table_flush(h, table);
-}
-
static const struct nft_xt_restore_cb ebt_restore_cb = {
.commit = nft_bridge_commit,
- .table_new = nft_table_new,
- .table_flush = ebt_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandeb,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
static const struct option ebt_restore_options[] = {
@@ -539,18 +449,18 @@ int xtables_eb_restore_main(int argc, char *argv[])
nft_init_eb(&h, "ebtables-restore");
h.noflush = noflush;
xtables_restore_parse(&h, &p);
- nft_fini(&h);
+ nft_fini_eb(&h);
return 0;
}
static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandarp,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
int xtables_arp_restore_main(int argc, char *argv[])
@@ -564,6 +474,7 @@ int xtables_arp_restore_main(int argc, char *argv[])
nft_init_arp(&h, "arptables-restore");
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
return 0;
}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 3a52f8c3..bb3d8cd3 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -32,7 +32,7 @@
#define prog_name xtables_globals.program_name
#define prog_vers xtables_globals.program_version
-static const char *ipt_save_optstring = "bcdt:M:f:46V";
+static const char *ipt_save_optstring = "bcdt:M:f:V";
static const struct option ipt_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
@@ -40,8 +40,6 @@ static const struct option ipt_save_options[] = {
{.name = "table", .has_arg = true, .val = 't'},
{.name = "modprobe", .has_arg = true, .val = 'M'},
{.name = "file", .has_arg = true, .val = 'f'},
- {.name = "ipv4", .has_arg = false, .val = '4'},
- {.name = "ipv6", .has_arg = false, .val = '6'},
{NULL},
};
@@ -139,10 +137,8 @@ xtables_save_main(int family, int argc, char *argv[],
struct do_output_data d = {
.format = FMT_NOCOUNTS,
};
+ struct nft_handle h;
bool dump = false;
- struct nft_handle h = {
- .family = family,
- };
FILE *file = NULL;
int ret, c;
@@ -189,13 +185,6 @@ xtables_save_main(int family, int argc, char *argv[],
case 'd':
dump = true;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'V':
printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
exit(0);
@@ -242,19 +231,20 @@ xtables_save_main(int family, int argc, char *argv[],
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
exit(EXIT_FAILURE);
}
- h.ops = nft_family_ops_lookup(h.family);
- if (!h.ops)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
+ nft_cache_level_set(&h, NFT_CL_RULES, NULL);
+ nft_cache_build(&h);
ret = do_output(&h, tablename, &d);
nft_fini(&h);
+ xtables_fini();
if (dump)
exit(0);
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 1a28c548..dd6fb791 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -44,9 +44,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
{
int ret;
char *table = "filter";
- struct nft_handle h = {
- .family = family,
- };
+ struct nft_handle h;
xtables_globals.program_name = progname;
ret = xtables_init_all(&xtables_globals, family);
@@ -61,7 +59,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
init_extensions4();
#endif
- if (nft_init(&h, xtables_ipv4) < 0) {
+ if (nft_init(&h, family, xtables_ipv4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -74,6 +72,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret) {
if (errno == EINVAL) {
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 0f95855b..5aa42496 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -480,7 +480,7 @@ static int xtables_xlate_main_common(struct nft_handle *h,
return 1;
}
- if (nft_init(h, tables) < 0) {
+ if (nft_init(h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -509,6 +509,7 @@ static int xtables_xlate_main(int family, const char *progname, int argc,
fprintf(stderr, "Translation not implemented\n");
nft_fini(&h);
+ xtables_fini();
exit(!ret);
}
@@ -563,6 +564,7 @@ static int xtables_restore_xlate_main(int family, const char *progname,
printf("# Completed on %s", ctime(&now));
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
exit(0);
}
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 8f9dc628..9d2e441e 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -161,7 +161,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(const struct xtables_rule_match *matches)
+printhelp(const struct xtables_rule_match *matches)
{
printf("%s v%s\n\n"
"Usage: %s -[ACD] chain rule-specification [options]\n"
@@ -240,7 +240,6 @@ exit_printhelp(const struct xtables_rule_match *matches)
"[!] --version -V print package version.\n");
print_extension_helps(xtables_targets, matches);
- exit(0);
}
void
@@ -361,11 +360,11 @@ add_entry(const char *chain,
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -381,11 +380,11 @@ add_entry(const char *chain,
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -418,7 +417,7 @@ replace_entry(const char *chain, const char *table,
} else
return 1;
- return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -440,7 +439,7 @@ delete_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -453,7 +452,7 @@ delete_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
}
@@ -480,7 +479,7 @@ check_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -493,7 +492,7 @@ check_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
}
@@ -524,7 +523,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -534,7 +533,7 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
if (counters)
counters = -1; /* iptables -c format */
- return nft_rule_list_save(h, chain, table, rulenum, counters);
+ return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
void do_parse(struct nft_handle *h, int argc, char *argv[],
@@ -571,10 +570,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
demand-load a protocol. */
opterr = 0;
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
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:fbvw::W::nt:m:xc:g:46",
@@ -728,7 +723,9 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
xtables_find_match(cs->protocol,
XTF_TRY_LOAD, &cs->matches);
- exit_printhelp(cs->matches);
+ printhelp(cs->matches);
+ p->command = CMD_NONE;
+ return;
/*
* Option selection
@@ -917,27 +914,22 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case '4':
+ if (args->family == AF_INET)
+ break;
+
if (p->restore && args->family == AF_INET6)
return;
- if (args->family != AF_INET)
- exit_tryhelp(2);
-
- h->ops = nft_family_ops_lookup(args->family);
- break;
+ exit_tryhelp(2);
case '6':
+ if (args->family == AF_INET6)
+ break;
+
if (p->restore && args->family == AF_INET)
return;
- args->family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
-
- h->ops = nft_family_ops_lookup(args->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Unknown family");
- break;
+ exit_tryhelp(2);
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
@@ -1031,11 +1023,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
opt2char(OPT_VIANAMEIN),
p->chain);
}
-
- if (!p->xlate && !cs->target && strlen(cs->jumpto) > 0 &&
- !nft_chain_exists(h, p->table, cs->jumpto))
- xtables_error(PARAMETER_PROBLEM,
- "Chain '%s' does not exist", cs->jumpto);
}
}
@@ -1066,8 +1053,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, p.chain, p.table,
- p.rulenum - 1, p.verbose);
+ ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
+ p.rulenum - 1, p.verbose);
break;
case CMD_CHECK:
ret = check_entry(p.chain, p.table, &cs, h->family,
@@ -1085,15 +1072,15 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options&OPT_VERBOSE, h, false);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO_NUM:
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
break;
case CMD_LIST:
@@ -1105,11 +1092,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_EXPANDED,
cs.options & OPT_LINENUMBERS);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
@@ -1120,27 +1107,27 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = list_rules(h, p.chain, p.table, p.rulenum,
cs.options & OPT_VERBOSE);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, p.chain, p.table);
+ ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, p.chain, p.table,
+ ret = nft_cmd_chain_user_del(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, p.chain, p.table, p.newname);
+ ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
+ ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
break;
case CMD_NONE:
/* do_parse ignored the line (eg: -4 with ip6tables-restore) */
@@ -1152,11 +1139,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
*table = p.table;
- xtables_rule_matches_free(&cs.matches);
- if (cs.target) {
- free(cs.target->t);
- cs.target->t = NULL;
- }
+ nft_clear_iptables_command_state(&cs);
if (h->family == AF_INET) {
free(args.s.addr.v4);
diff --git a/libiptc/libip4tc.c b/libiptc/libip4tc.c
index 55540638..78a896f7 100644
--- a/libiptc/libip4tc.c
+++ b/libiptc/libip4tc.c
@@ -22,7 +22,7 @@
#define inline
#endif
-#if !defined(__GLIBC__) || (__GLIBC__ < 2)
+#if !defined(__BIONIC__) && (!defined(__GLIBC__) || (__GLIBC__ < 2))
typedef unsigned int socklen_t;
#endif
diff --git a/libiptc/libip6tc.c b/libiptc/libip6tc.c
index b7dd1e33..06cd6237 100644
--- a/libiptc/libip6tc.c
+++ b/libiptc/libip6tc.c
@@ -23,7 +23,7 @@
#define inline
#endif
-#if !defined(__GLIBC__) || (__GLIBC__ < 2)
+#if !defined(__BIONIC__) && (!defined(__GLIBC__) || (__GLIBC__ < 2))
typedef unsigned int socklen_t;
#endif
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 777c2b08..7fe42580 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -206,6 +206,38 @@ struct xtables_target *xtables_targets;
static bool xtables_fully_register_pending_match(struct xtables_match *me);
static bool xtables_fully_register_pending_target(struct xtables_target *me);
+/* registry for loaded shared objects to close later */
+struct dlreg {
+ struct dlreg *next;
+ void *handle;
+};
+static struct dlreg *dlreg = NULL;
+
+static int dlreg_add(void *handle)
+{
+ struct dlreg *new = malloc(sizeof(*new));
+
+ if (!new)
+ return -1;
+
+ new->handle = handle;
+ new->next = dlreg;
+ dlreg = new;
+ return 0;
+}
+
+static void dlreg_free(void)
+{
+ struct dlreg *next;
+
+ while (dlreg) {
+ next = dlreg->next;
+ dlclose(dlreg->handle);
+ free(dlreg);
+ dlreg = next;
+ }
+}
+
void xtables_init(void)
{
xtables_libdir = getenv("XTABLES_LIBDIR");
@@ -233,6 +265,11 @@ void xtables_init(void)
xtables_libdir = XTABLES_LIBDIR;
}
+void xtables_fini(void)
+{
+ dlreg_free();
+}
+
void xtables_set_nfproto(uint8_t nfproto)
{
switch (nfproto) {
@@ -567,6 +604,8 @@ static void *load_extension(const char *search_path, const char *af_prefix,
next = dir + strlen(dir);
for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
+ void *handle;
+
snprintf(path, sizeof(path), "%.*s/%s%s.so",
(unsigned int)(next - dir), dir,
*prefix, name);
@@ -578,11 +617,14 @@ static void *load_extension(const char *search_path, const char *af_prefix,
strerror(errno));
return NULL;
}
- if (dlopen(path, RTLD_NOW) == NULL) {
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
fprintf(stderr, "%s: %s\n", path, dlerror());
break;
}
+ dlreg_add(handle);
+
if (is_target)
ptr = xtables_find_target(name, XTF_DONT_LOAD);
else
diff --git a/utils/nfnl_osf.c b/utils/nfnl_osf.c
index 15d53197..8008e83d 100644
--- a/utils/nfnl_osf.c
+++ b/utils/nfnl_osf.c
@@ -378,9 +378,11 @@ static int osf_load_line(char *buffer, int len, int del)
memset(buf, 0, sizeof(buf));
if (del)
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE,
+ NLM_F_ACK | NLM_F_REQUEST);
else
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD,
+ NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE);
nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
@@ -390,7 +392,7 @@ static int osf_load_line(char *buffer, int len, int del)
static int osf_load_entries(char *path, int del)
{
FILE *inf;
- int err = 0;
+ int err = 0, lineno = 0;
char buf[1024];
inf = fopen(path, "r");
@@ -400,7 +402,9 @@ static int osf_load_entries(char *path, int del)
}
while(fgets(buf, sizeof(buf), inf)) {
- int len;
+ int len, rc;
+
+ lineno++;
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
continue;
@@ -412,9 +416,11 @@ static int osf_load_entries(char *path, int del)
buf[len] = '\0';
- err = osf_load_line(buf, len, del);
- if (err)
- break;
+ rc = osf_load_line(buf, len, del);
+ if (rc && (!del || errno != ENOENT)) {
+ ulog_err("Failed to load line %d", lineno);
+ err = rc;
+ }
memset(buf, 0, sizeof(buf));
}
@@ -446,6 +452,7 @@ int main(int argc, char *argv[])
if (!fingerprints) {
err = -ENOENT;
+ ulog("Missing fingerprints file argument.\n");
goto err_out_exit;
}