aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2020-04-08 07:17:05 -0700
committerMaciej Żenczykowski <maze@google.com>2020-04-08 07:17:18 -0700
commitb68f7ec3cad0a37be41b5d25002714b73a7ec800 (patch)
treed2ba3d14795dab0c12cd6e365eadf46254e00387
parent2ca8cc154dd137be025a8cf20530d064ff731ac3 (diff)
parent1447b15100fe73810237809c1d4ade3c861b6d96 (diff)
downloadiptables-b68f7ec3cad0a37be41b5d25002714b73a7ec800.tar.gz
Merge tag 'v1.8.3' of git://git.netfilter.org/iptables into work
iptables 1.8.3 release Generated via: git fetch git://git.netfilter.org/iptables v1.8.3 git merge FETCH_HEAD Signed-off-by: Maciej Żenczykowski <maze@google.com> Change-Id: I21995a5fbd05ff46c91d74b96259ed94ef16ff13
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac7
-rw-r--r--extensions/GNUmakefile.in15
-rw-r--r--extensions/libarpt_CLASSIFY.t2
-rw-r--r--extensions/libarpt_MARK.t6
-rw-r--r--extensions/libarpt_mangle.t8
-rw-r--r--extensions/libarpt_standard.t4
-rw-r--r--extensions/libebt_802_3.c4
-rw-r--r--extensions/libebt_802_3.t2
-rw-r--r--extensions/libebt_arp.c14
-rw-r--r--extensions/libebt_arp.t8
-rw-r--r--extensions/libebt_ip.c16
-rw-r--r--extensions/libebt_ip.t6
-rw-r--r--extensions/libebt_ip6.c14
-rw-r--r--extensions/libebt_ip6.t6
-rw-r--r--extensions/libebt_mark_m.c2
-rw-r--r--extensions/libebt_mark_m.t4
-rw-r--r--extensions/libebt_pkttype.c5
-rw-r--r--extensions/libebt_pkttype.t13
-rw-r--r--extensions/libebt_standard.t4
-rw-r--r--extensions/libebt_stp.c5
-rw-r--r--extensions/libebt_vlan.c14
-rw-r--r--extensions/libebt_vlan.t10
-rw-r--r--extensions/libip6t_icmp6.c4
-rw-r--r--extensions/libip6t_mh.txlate4
-rw-r--r--extensions/libipt_icmp.c2
-rw-r--r--extensions/libipt_realm.man2
-rw-r--r--extensions/libxt_AUDIT.man6
-rw-r--r--extensions/libxt_CLASSIFY.c59
-rw-r--r--extensions/libxt_MARK.c95
-rw-r--r--extensions/libxt_SYNPROXY.man2
-rw-r--r--extensions/libxt_TRACE.man21
-rw-r--r--extensions/libxt_comment.t2
-rw-r--r--extensions/libxt_connlabel.c49
-rw-r--r--extensions/libxt_connlabel.t23
-rw-r--r--extensions/libxt_connlabel.txlate8
-rw-r--r--extensions/libxt_ipvs.c7
-rw-r--r--extensions/libxt_ipvs.t20
-rw-r--r--extensions/libxt_osf.man2
-rw-r--r--include/libiptc/xtcshared.h5
-rw-r--r--include/linux/netfilter.h2
-rw-r--r--iptables/.gitignore2
-rw-r--r--iptables/Makefile.am17
-rw-r--r--iptables/arptables-nft-restore.839
-rw-r--r--iptables/arptables-nft-save.847
-rw-r--r--iptables/arptables-nft.8348
-rw-r--r--iptables/ebtables-nft.81116
-rw-r--r--iptables/ip6tables-restore.c391
-rw-r--r--iptables/ip6tables-save.c203
-rw-r--r--iptables/ip6tables.c2
-rw-r--r--iptables/iptables-restore.c154
-rw-r--r--iptables/iptables-save.8.in7
-rw-r--r--iptables/iptables-save.c179
-rw-r--r--iptables/iptables.c2
-rw-r--r--iptables/nft-arp.c178
-rw-r--r--iptables/nft-arp.h2
-rw-r--r--iptables/nft-bridge.c43
-rw-r--r--iptables/nft-bridge.h2
-rw-r--r--iptables/nft-ipv4.c14
-rw-r--r--iptables/nft-ipv6.c14
-rw-r--r--iptables/nft-shared.c97
-rw-r--r--iptables/nft-shared.h20
-rw-r--r--iptables/nft.c2000
-rw-r--r--iptables/nft.h50
-rwxr-xr-xiptables/tests/shell/run-tests.sh48
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0001-arptables-save-restore_032
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_06
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_064
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_07
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0117
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0004-restore-race_0118
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0002-verbose-output_013
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_063
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0005-delete-rules_014
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0005-rule-replace_038
-rw-r--r--iptables/xshared.c50
-rw-r--r--iptables/xshared.h2
-rw-r--r--iptables/xtables-arp.c19
-rw-r--r--iptables/xtables-eb-standalone.c2
-rw-r--r--iptables/xtables-eb-translate.c24
-rw-r--r--iptables/xtables-eb.c84
-rw-r--r--iptables/xtables-legacy-multi.c1
-rw-r--r--iptables/xtables-legacy.82
-rw-r--r--iptables/xtables-monitor.c31
-rw-r--r--iptables/xtables-restore.c108
-rw-r--r--iptables/xtables-save.c28
-rw-r--r--iptables/xtables-translate.89
-rw-r--r--iptables/xtables-translate.c8
-rw-r--r--iptables/xtables.c17
-rw-r--r--libiptc/Makefile.am4
-rw-r--r--libiptc/libiptc.c4
-rw-r--r--libxtables/xtables.c18
-rw-r--r--release.sh31
-rw-r--r--utils/.gitignore1
-rw-r--r--utils/Makefile.am3
-rw-r--r--utils/nfbpf_compile.8.in70
-rwxr-xr-xxlate-test.py14
97 files changed, 4184 insertions, 2277 deletions
diff --git a/Makefile.am b/Makefile.am
index 044f6461..b1ba015f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,7 +26,7 @@ tarball:
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
pushd ${top_srcdir} && git archive --prefix=${PACKAGE_TARNAME}-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
pushd /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION} && ./autogen.sh && popd;
- tar --exclude=*.t --exclude=iptables-test.py -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
+ tar -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
config.status: extensions/GNUmakefile.in \
diff --git a/configure.ac b/configure.ac
index 448ec918..b94512d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
-AC_INIT([iptables], [1.8.2])
+AC_INIT([iptables], [1.8.3])
# See libtool.info "Libtool's versioning system"
libxtables_vcurrent=14
@@ -136,7 +136,7 @@ if test "x$enable_nftables" = "xyes"; then
exit 1
fi
- PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.1], [nftables=1], [nftables=0])
+ PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.3], [nftables=1], [nftables=0])
if test "$nftables" = 0;
then
@@ -252,7 +252,8 @@ AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile
libxtables/Makefile utils/Makefile
include/xtables-version.h include/iptables/internal.h
iptables/xtables-monitor.8
- utils/nfnl_osf.8])
+ utils/nfnl_osf.8
+ utils/nfbpf_compile.8])
AC_OUTPUT
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index c0d73cd2..0842a553 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -55,11 +55,12 @@ pfb_objs := $(patsubst %,libebt_%.o,${pfb_build_mod})
pfa_objs := $(patsubst %,libarpt_%.o,${pfa_build_mod})
pf4_objs := $(patsubst %,libipt_%.o,${pf4_build_mod})
pf6_objs := $(patsubst %,libip6t_%.o,${pf6_build_mod})
-pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks})
+pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod})
pfb_solibs := $(patsubst %,libebt_%.so,${pfb_build_mod})
pfa_solibs := $(patsubst %,libarpt_%.so,${pfa_build_mod})
pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod})
pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod})
+pfx_symlink_files := $(patsubst %,libxt_%.so,${pfx_symlinks})
#
@@ -72,8 +73,9 @@ targets_install :=
@ENABLE_STATIC_TRUE@ libext_arpt_objs := ${pfa_objs}
@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs}
@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs}
-@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs}
+@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs} ${pfx_symlink_files}
@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs}
+@ENABLE_STATIC_FALSE@ symlinks_install := ${pfx_symlink_files}
.SECONDARY:
@@ -81,9 +83,14 @@ targets_install :=
all: ${targets}
-install: ${targets_install}
+install: ${targets_install} ${symlinks_install}
@mkdir -p "${DESTDIR}${xtlibdir}";
- if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi;
+ if test -n "${targets_install}"; then \
+ install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/"; \
+ fi;
+ if test -n "${symlinks_install}"; then \
+ cp -P ${symlinks_install} "${DESTDIR}${xtlibdir}/"; \
+ fi;
clean:
rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c;
diff --git a/extensions/libarpt_CLASSIFY.t b/extensions/libarpt_CLASSIFY.t
index c30480d2..0cf0f2ce 100644
--- a/extensions/libarpt_CLASSIFY.t
+++ b/extensions/libarpt_CLASSIFY.t
@@ -1,4 +1,4 @@
:OUTPUT
-o lo --destination-mac 11:22:33:44:55:66;-o lo --dst-mac 11:22:33:44:55:66;OK
--dst-mac Broadcast ;--dst-mac ff:ff:ff:ff:ff:ff;OK
-! -o eth+ -d 1.2.3.4/24 -j CLASSIFY --set-class 0000:0000;! -o eth+ -d 1.2.3.0/24 --h-length 6 --h-type 1 -j CLASSIFY --set-class 0000:0000;OK
+! -o eth+ -d 1.2.3.4/24 -j CLASSIFY --set-class 0:0;-j CLASSIFY ! -o eth+ -d 1.2.3.0/24 --set-class 0:0;OK
diff --git a/extensions/libarpt_MARK.t b/extensions/libarpt_MARK.t
index cb4c2cb6..3b13d44f 100644
--- a/extensions/libarpt_MARK.t
+++ b/extensions/libarpt_MARK.t
@@ -1,4 +1,4 @@
:INPUT,OUTPUT
--d 0.0.0.0/8 -j MARK --set-mark 0x1;-d 0.0.0.0/8 --h-length 6 --h-type 1 -j MARK --set-xmark 0x1/0xffffffff;OK
--s ! 0.0.0.0 -j MARK --and-mark 0x17;! -s 0.0.0.0 --h-length 6 --h-type 1 -j MARK --set-xmark 0x0/0xffffffe8;OK
--s 0.0.0.0 -j MARK --or-mark 0x17;-s 0.0.0.0 --h-length 6 --h-type 1 -j MARK --set-xmark 0x17/0x17;OK
+-j MARK -d 0.0.0.0/8 --set-mark 1;=;OK
+-s ! 0.0.0.0 -j MARK --and-mark 0x17;-j MARK ! -s 0.0.0.0 --and-mark 17;OK
+-j MARK -s 0.0.0.0 --or-mark 17;=;OK
diff --git a/extensions/libarpt_mangle.t b/extensions/libarpt_mangle.t
index 1d4c3977..da966948 100644
--- a/extensions/libarpt_mangle.t
+++ b/extensions/libarpt_mangle.t
@@ -1,5 +1,5 @@
:OUTPUT
--s 1.2.3.4 -j mangle --mangle-ip-s 1.2.3.5;-s 1.2.3.4 --h-length 6 --h-type 1 -j mangle --mangle-ip-s 1.2.3.5;OK
--d 1.2.3.4 -j mangle --mangle-ip-d 1.2.3.5;-d 1.2.3.4 --h-length 6 --h-type 1 -j mangle --mangle-ip-d 1.2.3.5;OK
--d 1.2.3.4 --h-length 6 --h-type 1 -j mangle --mangle-mac-d 00:01:02:03:04:05;=;OK
--d 1.2.3.4 -j mangle --mangle-mac-s 00:01:02:03:04:05;=;FAIL
+-j mangle -s 1.2.3.4 --mangle-ip-s 1.2.3.5;=;OK
+-j mangle -d 1.2.3.4 --mangle-ip-d 1.2.3.5;=;OK
+-j mangle -d 1.2.3.4 --mangle-mac-d 00:01:02:03:04:05;=;OK
+-d 1.2.3.4 --h-length 5 -j mangle --mangle-mac-s 00:01:02:03:04:05;=;FAIL
diff --git a/extensions/libarpt_standard.t b/extensions/libarpt_standard.t
index bef682af..e84a00b7 100644
--- a/extensions/libarpt_standard.t
+++ b/extensions/libarpt_standard.t
@@ -5,8 +5,8 @@
-d 192.168.0.1;=;OK
! -d 0.0.0.0;=;OK
-d 0.0.0.0/24;=;OK
--i lo;=;OK
-! -i lo;=;OK
+-j DROP -i lo;=;OK
+-j ACCEPT ! -i lo;=;OK
-i ppp+;=;OK
! -i ppp+;=;OK
-i lo --destination-mac 11:22:33:44:55:66;-i lo --dst-mac 11:22:33:44:55:66;OK
diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c
index 9e91d052..f05d02ea 100644
--- a/extensions/libebt_802_3.c
+++ b/extensions/libebt_802_3.c
@@ -98,15 +98,15 @@ static void br802_3_print(const void *ip, const struct xt_entry_match *match,
struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data;
if (info->bitmask & EBT_802_3_SAP) {
+ printf("--802_3-sap ");
if (info->invflags & EBT_802_3_SAP)
printf("! ");
- printf("--802_3-sap ");
printf("0x%.2x ", info->sap);
}
if (info->bitmask & EBT_802_3_TYPE) {
+ printf("--802_3-type ");
if (info->invflags & EBT_802_3_TYPE)
printf("! ");
- printf("--802_3-type ");
printf("0x%.4x ", ntohs(info->type));
}
}
diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t
index 61081bd6..ddfb2f0a 100644
--- a/extensions/libebt_802_3.t
+++ b/extensions/libebt_802_3.t
@@ -1,3 +1,3 @@
:INPUT,FORWARD,OUTPUT
-! --802_3-sap 0x0a -j CONTINUE;=;OK
+--802_3-sap ! 0x0a -j CONTINUE;=;OK
--802_3-type 0x000a -j RETURN;=;OK
diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c
index c1b0ab1d..a062b7e7 100644
--- a/extensions/libebt_arp.c
+++ b/extensions/libebt_arp.c
@@ -338,51 +338,51 @@ static void brarp_print(const void *ip, const struct xt_entry_match *match, int
if (arpinfo->bitmask & EBT_ARP_OPCODE) {
int opcode = ntohs(arpinfo->opcode);
+ printf("--arp-op ");
if (arpinfo->invflags & EBT_ARP_OPCODE)
printf("! ");
- printf("--arp-op ");
if (opcode > 0 && opcode <= ARRAY_SIZE(opcodes))
printf("%s ", opcodes[opcode - 1]);
else
printf("%d ", opcode);
}
if (arpinfo->bitmask & EBT_ARP_HTYPE) {
+ printf("--arp-htype ");
if (arpinfo->invflags & EBT_ARP_HTYPE)
printf("! ");
- printf("--arp-htype ");
printf("%d ", ntohs(arpinfo->htype));
}
if (arpinfo->bitmask & EBT_ARP_PTYPE) {
+ printf("--arp-ptype ");
if (arpinfo->invflags & EBT_ARP_PTYPE)
printf("! ");
- printf("--arp-ptype ");
printf("0x%x ", ntohs(arpinfo->ptype));
}
if (arpinfo->bitmask & EBT_ARP_SRC_IP) {
+ printf("--arp-ip-src ");
if (arpinfo->invflags & EBT_ARP_SRC_IP)
printf("! ");
- printf("--arp-ip-src ");
printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->saddr),
xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->smsk));
}
if (arpinfo->bitmask & EBT_ARP_DST_IP) {
+ printf("--arp-ip-dst ");
if (arpinfo->invflags & EBT_ARP_DST_IP)
printf("! ");
- printf("--arp-ip-dst ");
printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->daddr),
xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->dmsk));
}
if (arpinfo->bitmask & EBT_ARP_SRC_MAC) {
+ printf("--arp-mac-src ");
if (arpinfo->invflags & EBT_ARP_SRC_MAC)
printf("! ");
- printf("--arp-mac-src ");
xtables_print_mac_and_mask(arpinfo->smaddr, arpinfo->smmsk);
printf(" ");
}
if (arpinfo->bitmask & EBT_ARP_DST_MAC) {
+ printf("--arp-mac-dst ");
if (arpinfo->invflags & EBT_ARP_DST_MAC)
printf("! ");
- printf("--arp-mac-dst ");
xtables_print_mac_and_mask(arpinfo->dmaddr, arpinfo->dmmsk);
printf(" ");
}
diff --git a/extensions/libebt_arp.t b/extensions/libebt_arp.t
index a05ab12d..14ff0f09 100644
--- a/extensions/libebt_arp.t
+++ b/extensions/libebt_arp.t
@@ -1,11 +1,11 @@
:INPUT,FORWARD,OUTPUT
-p ARP --arp-op Request;=;OK
--p ARP ! --arp-htype 1;=;OK
+-p ARP --arp-htype ! 1;=;OK
-p ARP --arp-ptype 0x2;=;OK
-p ARP --arp-ip-src 1.2.3.4;=;OK
--p ARP ! --arp-ip-dst 1.2.3.4;=;OK
--p ARP ! --arp-ip-src 0.0.0.0;=;OK
--p ARP ! --arp-ip-dst 0.0.0.0/8;=;OK
+-p ARP ! --arp-ip-dst 1.2.3.4;-p ARP --arp-ip-dst ! 1.2.3.4 -j CONTINUE;OK
+-p ARP --arp-ip-src ! 0.0.0.0;=;OK
+-p ARP --arp-ip-dst ! 0.0.0.0/8;=;OK
-p ARP --arp-mac-src 00:de:ad:be:ef:00;=;OK
-p ARP --arp-mac-dst de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
-p ARP --arp-gratuitous;=;OK
diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
index d48704fe..acb9bfcd 100644
--- a/extensions/libebt_ip.c
+++ b/extensions/libebt_ip.c
@@ -472,35 +472,35 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
struct in_addr *addrp, *maskp;
if (info->bitmask & EBT_IP_SOURCE) {
+ printf("--ip-src ");
if (info->invflags & EBT_IP_SOURCE)
printf("! ");
- printf("--ip-src ");
addrp = (struct in_addr *)&info->saddr;
maskp = (struct in_addr *)&info->smsk;
printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
xtables_ipmask_to_numeric(maskp));
}
if (info->bitmask & EBT_IP_DEST) {
+ printf("--ip-dst ");
if (info->invflags & EBT_IP_DEST)
printf("! ");
- printf("--ip-dst ");
addrp = (struct in_addr *)&info->daddr;
maskp = (struct in_addr *)&info->dmsk;
printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
xtables_ipmask_to_numeric(maskp));
}
if (info->bitmask & EBT_IP_TOS) {
+ printf("--ip-tos ");
if (info->invflags & EBT_IP_TOS)
printf("! ");
- printf("--ip-tos ");
printf("0x%02X ", info->tos);
}
if (info->bitmask & EBT_IP_PROTO) {
struct protoent *pe;
+ printf("--ip-proto ");
if (info->invflags & EBT_IP_PROTO)
printf("! ");
- printf("--ip-proto ");
pe = getprotobynumber(info->protocol);
if (pe == NULL) {
printf("%d ", info->protocol);
@@ -509,28 +509,28 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
}
}
if (info->bitmask & EBT_IP_SPORT) {
+ printf("--ip-sport ");
if (info->invflags & EBT_IP_SPORT)
printf("! ");
- printf("--ip-sport ");
print_port_range(info->sport);
}
if (info->bitmask & EBT_IP_DPORT) {
+ printf("--ip-dport ");
if (info->invflags & EBT_IP_DPORT)
printf("! ");
- printf("--ip-dport ");
print_port_range(info->dport);
}
if (info->bitmask & EBT_IP_ICMP) {
+ printf("--ip-icmp-type ");
if (info->invflags & EBT_IP_ICMP)
printf("! ");
- printf("--ip-icmp-type ");
ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
info->icmp_type, info->icmp_code);
}
if (info->bitmask & EBT_IP_IGMP) {
+ printf("--ip-igmp-type ");
if (info->invflags & EBT_IP_IGMP)
printf("! ");
- printf("--ip-igmp-type ");
ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
info->igmp_type, NULL);
}
diff --git a/extensions/libebt_ip.t b/extensions/libebt_ip.t
index 01a91a73..8be5dfbb 100644
--- a/extensions/libebt_ip.t
+++ b/extensions/libebt_ip.t
@@ -1,13 +1,13 @@
:INPUT,FORWARD,OUTPUT
--p ip --ip-src ! 192.168.0.0/24 -j ACCEPT;-p IPv4 ! --ip-src 192.168.0.0/24 -j ACCEPT;OK
+-p ip --ip-src ! 192.168.0.0/24 -j ACCEPT;-p IPv4 --ip-src ! 192.168.0.0/24 -j ACCEPT;OK
-p IPv4 --ip-dst 10.0.0.1;=;OK
-p IPv4 --ip-tos 0xFF;=;OK
--p IPv4 ! --ip-tos 0xFF;=;OK
+-p IPv4 --ip-tos ! 0xFF;=;OK
-p IPv4 --ip-proto tcp --ip-dport 22;=;OK
-p IPv4 --ip-proto udp --ip-sport 1024:65535;=;OK
-p IPv4 --ip-proto 253;=;OK
-p IPv4 --ip-proto icmp --ip-icmp-type echo-request;=;OK
-p IPv4 --ip-proto icmp --ip-icmp-type 1/1;=;OK
--p ip --ip-protocol icmp --ip-icmp-type ! 1:10;-p IPv4 --ip-proto icmp ! --ip-icmp-type 1:10/0:255 -j CONTINUE;OK
+-p ip --ip-protocol icmp --ip-icmp-type ! 1:10;-p IPv4 --ip-proto icmp --ip-icmp-type ! 1:10/0:255 -j CONTINUE;OK
--ip-proto icmp --ip-icmp-type 1/1;=;FAIL
! -p ip --ip-proto icmp --ip-icmp-type 1/1;=;FAIL
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c
index b7277649..b8a5a5d8 100644
--- a/extensions/libebt_ip6.c
+++ b/extensions/libebt_ip6.c
@@ -399,31 +399,31 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match,
struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
if (ipinfo->bitmask & EBT_IP6_SOURCE) {
+ printf("--ip6-src ");
if (ipinfo->invflags & EBT_IP6_SOURCE)
printf("! ");
- printf("--ip6-src ");
printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr));
printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk));
}
if (ipinfo->bitmask & EBT_IP6_DEST) {
+ printf("--ip6-dst ");
if (ipinfo->invflags & EBT_IP6_DEST)
printf("! ");
- printf("--ip6-dst ");
printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr));
printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->dmsk));
}
if (ipinfo->bitmask & EBT_IP6_TCLASS) {
+ printf("--ip6-tclass ");
if (ipinfo->invflags & EBT_IP6_TCLASS)
printf("! ");
- printf("--ip6-tclass ");
printf("0x%02X ", ipinfo->tclass);
}
if (ipinfo->bitmask & EBT_IP6_PROTO) {
struct protoent *pe;
+ printf("--ip6-proto ");
if (ipinfo->invflags & EBT_IP6_PROTO)
printf("! ");
- printf("--ip6-proto ");
pe = getprotobynumber(ipinfo->protocol);
if (pe == NULL) {
printf("%d ", ipinfo->protocol);
@@ -432,21 +432,21 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match,
}
}
if (ipinfo->bitmask & EBT_IP6_SPORT) {
+ printf("--ip6-sport ");
if (ipinfo->invflags & EBT_IP6_SPORT)
printf("! ");
- printf("--ip6-sport ");
print_port_range(ipinfo->sport);
}
if (ipinfo->bitmask & EBT_IP6_DPORT) {
+ printf("--ip6-dport ");
if (ipinfo->invflags & EBT_IP6_DPORT)
printf("! ");
- printf("--ip6-dport ");
print_port_range(ipinfo->dport);
}
if (ipinfo->bitmask & EBT_IP6_ICMP6) {
+ printf("--ip6-icmp-type ");
if (ipinfo->invflags & EBT_IP6_ICMP6)
printf("! ");
- printf("--ip6-icmp-type ");
print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
}
}
diff --git a/extensions/libebt_ip6.t b/extensions/libebt_ip6.t
index 6b3221ea..fa1038af 100644
--- a/extensions/libebt_ip6.t
+++ b/extensions/libebt_ip6.t
@@ -1,15 +1,15 @@
:INPUT,FORWARD,OUTPUT
--p ip6 ! --ip6-src dead::beef/64 -j ACCEPT;-p IPv6 ! --ip6-src dead::/64 -j ACCEPT;OK
+-p ip6 --ip6-src ! dead::beef/64 -j ACCEPT;-p IPv6 --ip6-src ! dead::/64 -j ACCEPT;OK
-p IPv6 --ip6-dst dead:beef::/64 -j ACCEPT;=;OK
-p IPv6 --ip6-dst f00:ba::;=;OK
-p IPv6 --ip6-tclass 0xFF;=;OK
-p IPv6 --ip6-proto tcp --ip6-dport 22;=;OK
--p IPv6 --ip6-proto tcp ! --ip6-dport 22;=;OK
+-p IPv6 --ip6-proto tcp --ip6-dport ! 22;=;OK
-p IPv6 --ip6-proto udp --ip6-sport 1024:65535;=;OK
-p IPv6 --ip6-proto 253;=;OK
-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request -j CONTINUE;=;OK
-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request;=;OK
-p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1;-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type communication-prohibited -j CONTINUE;OK
--p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;OK
+-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type ! 1:10/0:255;=;OK
--ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL
! -p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL
diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c
index 64ad926f..2462d0af 100644
--- a/extensions/libebt_mark_m.c
+++ b/extensions/libebt_mark_m.c
@@ -86,9 +86,9 @@ static void brmark_m_print(const void *ip, const struct xt_entry_match *match,
{
struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data;
+ printf("--mark ");
if (info->invert)
printf("! ");
- printf("--mark ");
if (info->bitmask == EBT_MARK_OR)
printf("/0x%lx ", info->mask);
else if (info->mask != 0xffffffff)
diff --git a/extensions/libebt_mark_m.t b/extensions/libebt_mark_m.t
index 9ad41704..00035427 100644
--- a/extensions/libebt_mark_m.t
+++ b/extensions/libebt_mark_m.t
@@ -1,6 +1,6 @@
:INPUT,FORWARD,OUTPUT
--mark 42;--mark 0x2a;OK
---mark ! 42;! --mark 0x2a;OK
+--mark ! 42;--mark ! 0x2a;OK
--mark 42/0xff;--mark 0x2a/0xff;OK
-! --mark 0x1/0xff;=;OK
+--mark ! 0x1/0xff;=;OK
--mark /0x2;=;OK
diff --git a/extensions/libebt_pkttype.c b/extensions/libebt_pkttype.c
index 265674d1..4e2d19de 100644
--- a/extensions/libebt_pkttype.c
+++ b/extensions/libebt_pkttype.c
@@ -75,10 +75,7 @@ static void brpkttype_print(const void *ip, const struct xt_entry_match *match,
{
struct ebt_pkttype_info *pt = (struct ebt_pkttype_info *)match->data;
- if (pt->invert)
- printf("! ");
-
- printf("--pkttype-type ");
+ printf("--pkttype-type %s", pt->invert ? "! " : "");
if (pt->pkt_type < ARRAY_SIZE(classes))
printf("%s ", classes[pt->pkt_type]);
diff --git a/extensions/libebt_pkttype.t b/extensions/libebt_pkttype.t
index f870f5c7..e3b95ded 100644
--- a/extensions/libebt_pkttype.t
+++ b/extensions/libebt_pkttype.t
@@ -1,13 +1,14 @@
:INPUT,FORWARD,OUTPUT
+! --pkttype-type host;--pkttype-type ! host -j CONTINUE;OK
--pkttype-type host;=;OK
-! --pkttype-type host;=;OK
+--pkttype-type ! host;=;OK
--pkttype-type broadcast;=;OK
-! --pkttype-type broadcast;=;OK
+--pkttype-type ! broadcast;=;OK
--pkttype-type multicast;=;OK
-! --pkttype-type multicast;=;OK
+--pkttype-type ! multicast;=;OK
--pkttype-type otherhost;=;OK
-! --pkttype-type otherhost;=;OK
+--pkttype-type ! otherhost;=;OK
--pkttype-type outgoing;=;OK
-! --pkttype-type outgoing;=;OK
+--pkttype-type ! outgoing;=;OK
--pkttype-type loopback;=;OK
-! --pkttype-type loopback;=;OK
+--pkttype-type ! loopback;=;OK
diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t
index 72081fd6..0d678fb2 100644
--- a/extensions/libebt_standard.t
+++ b/extensions/libebt_standard.t
@@ -6,6 +6,6 @@
-d de:ad:be:ef:00:00 -j CONTINUE;=;OK
-d de:ad:be:ef:0:00/ff:ff:ff:ff:0:0 -j DROP;-d de:ad:be:ef:00:00/ff:ff:ff:ff:00:00 -j DROP;OK
-p ARP -j ACCEPT;=;OK
-! -p ARP -j ACCEPT;=;OK
+-p ! ARP -j ACCEPT;=;OK
-p 0 -j ACCEPT;=;FAIL
-! -p 0 -j ACCEPT;=;FAIL
+-p ! 0 -j ACCEPT;=;FAIL
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 33e4c8d9..06cf93b8 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -307,9 +307,8 @@ static void brstp_print(const void *ip, const struct xt_entry_match *match,
for (i = 0; i < STP_NUMOPS; i++) {
if (!(stpinfo->bitmask & (1 << i)))
continue;
- if (stpinfo->invflags & (1 << i))
- printf("! ");
- printf("--%s ", brstp_opts[i].name);
+ printf("--%s %s", brstp_opts[i].name,
+ (stpinfo->invflags & (1 << i)) ? "! " : "");
if (EBT_STP_TYPE == (1 << i)) {
if (stpinfo->type == BPDU_TYPE_CONFIG)
printf("%s", BPDU_TYPE_CONFIG_STRING);
diff --git a/extensions/libebt_vlan.c b/extensions/libebt_vlan.c
index 4a2eb712..fa697921 100644
--- a/extensions/libebt_vlan.c
+++ b/extensions/libebt_vlan.c
@@ -12,6 +12,7 @@
#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
+#include <netinet/if_ether.h>
#include <linux/netfilter_bridge/ebt_vlan.h>
#include <linux/if_ether.h>
#include "iptables/nft.h"
@@ -108,19 +109,14 @@ static void brvlan_print(const void *ip, const struct xt_entry_match *match,
struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
if (vlaninfo->bitmask & EBT_VLAN_ID) {
- if (vlaninfo->invflags & EBT_VLAN_ID)
- printf("! ");
- printf("--vlan-id %d ", vlaninfo->id);
+ printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id);
}
if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
- if (vlaninfo->invflags & EBT_VLAN_PRIO)
- printf("! ");
- printf("--vlan-prio %d ", vlaninfo->prio);
+ printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio);
}
if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
- if (vlaninfo->invflags & EBT_VLAN_ENCAP)
- printf("! ");
- printf("--vlan-encap %4.4X ", ntohs(vlaninfo->encap));
+ printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "");
+ printf("%4.4X ", ntohs(vlaninfo->encap));
}
}
diff --git a/extensions/libebt_vlan.t b/extensions/libebt_vlan.t
index 106374cd..81c79585 100644
--- a/extensions/libebt_vlan.t
+++ b/extensions/libebt_vlan.t
@@ -1,13 +1,13 @@
:INPUT,FORWARD,OUTPUT
-p 802_1Q --vlan-id 42;=;OK
--p 802_1Q ! --vlan-id 42;=;OK
+-p 802_1Q --vlan-id ! 42;=;OK
-p 802_1Q --vlan-prio 1;=;OK
--p 802_1Q ! --vlan-prio 1;=;OK
+-p 802_1Q --vlan-prio ! 1;=;OK
-p 802_1Q --vlan-encap ip;-p 802_1Q --vlan-encap 0800 -j CONTINUE;OK
-p 802_1Q --vlan-encap 0800 ;=;OK
--p 802_1Q ! --vlan-encap 0800 ;=;OK
--p 802_1Q --vlan-encap IPv6 ! --vlan-id 1;-p 802_1Q ! --vlan-id 1 --vlan-encap 86DD -j CONTINUE;OK
--p 802_1Q ! --vlan-id 1 --vlan-encap 86DD;=;OK
+-p 802_1Q --vlan-encap ! 0800 ;=;OK
+-p 802_1Q --vlan-encap IPv6 ! --vlan-id 1;-p 802_1Q --vlan-id ! 1 --vlan-encap 86DD -j CONTINUE;OK
+-p 802_1Q --vlan-id ! 1 --vlan-encap 86DD;=;OK
--vlan-encap ip;=;FAIL
--vlan-id 2;=;FAIL
--vlan-prio 1;=;FAIL
diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c
index 45a71875..cc7bfaeb 100644
--- a/extensions/libip6t_icmp6.c
+++ b/extensions/libip6t_icmp6.c
@@ -230,7 +230,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
type_name = icmp6_type_xlate(icmptype);
if (type_name) {
- xt_xlate_add(xl, type_name);
+ xt_xlate_add(xl, "%s", type_name);
} else {
for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
if (icmpv6_codes[i].type == icmptype &&
@@ -239,7 +239,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
break;
if (i != ARRAY_SIZE(icmpv6_codes))
- xt_xlate_add(xl, icmpv6_codes[i].name);
+ xt_xlate_add(xl, "%s", icmpv6_codes[i].name);
else
return 0;
}
diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate
index ccc07c3d..f5d638c0 100644
--- a/extensions/libip6t_mh.txlate
+++ b/extensions/libip6t_mh.txlate
@@ -1,5 +1,5 @@
ip6tables-translate -A INPUT -p mh --mh-type 1 -j ACCEPT
-nft add rule ip6 filter INPUT meta l4proto 135 mh type 1 counter accept
+nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept
ip6tables-translate -A INPUT -p mh --mh-type 1:3 -j ACCEPT
-nft add rule ip6 filter INPUT meta l4proto 135 mh type 1-3 counter accept
+nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index 54189976..e76257c5 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -236,7 +236,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
if (icmp_codes[i].type == icmptype &&
icmp_codes[i].code_min == code_min &&
icmp_codes[i].code_max == code_max) {
- xt_xlate_add(xl, icmp_codes[i].name);
+ xt_xlate_add(xl, "%s", icmp_codes[i].name);
return 1;
}
}
diff --git a/extensions/libipt_realm.man b/extensions/libipt_realm.man
index a40b1adc..72dff9b2 100644
--- a/extensions/libipt_realm.man
+++ b/extensions/libipt_realm.man
@@ -5,3 +5,5 @@ setups involving dynamic routing protocols like BGP.
Matches a given realm number (and optionally mask). If not a number, value
can be a named realm from /etc/iproute2/rt_realms (mask can not be used in
that case).
+Both value and mask are four byte unsigned integers and may be specified in
+decimal, hex (by prefixing with "0x") or octal (if a leading zero is given).
diff --git a/extensions/libxt_AUDIT.man b/extensions/libxt_AUDIT.man
index cd796967..4f5562e8 100644
--- a/extensions/libxt_AUDIT.man
+++ b/extensions/libxt_AUDIT.man
@@ -3,12 +3,14 @@ It can be used to record accepted, dropped, and rejected packets. See
auditd(8) for additional details.
.TP
\fB\-\-type\fP {\fBaccept\fP|\fBdrop\fP|\fBreject\fP}
-Set type of audit record.
+Set type of audit record. Starting with linux-4.12, this option has no effect
+on generated audit messages anymore. It is still accepted by iptables for
+compatibility reasons, but ignored.
.PP
Example:
.IP
iptables \-N AUDIT_DROP
.IP
-iptables \-A AUDIT_DROP \-j AUDIT \-\-type drop
+iptables \-A AUDIT_DROP \-j AUDIT
.IP
iptables \-A AUDIT_DROP \-j DROP
diff --git a/extensions/libxt_CLASSIFY.c b/extensions/libxt_CLASSIFY.c
index f90082dc..75aaf0c4 100644
--- a/extensions/libxt_CLASSIFY.c
+++ b/extensions/libxt_CLASSIFY.c
@@ -73,6 +73,24 @@ CLASSIFY_save(const void *ip, const struct xt_entry_target *target)
TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority));
}
+static void
+CLASSIFY_arp_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_classify_target_info *clinfo =
+ (const struct xt_classify_target_info *)target->data;
+
+ printf(" --set-class %x:%x",
+ TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority));
+}
+
+static void
+CLASSIFY_arp_print(const void *ip,
+ const struct xt_entry_target *target,
+ int numeric)
+{
+ CLASSIFY_arp_save(ip, target);
+}
+
static int CLASSIFY_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
@@ -98,21 +116,36 @@ static int CLASSIFY_xlate(struct xt_xlate *xl,
return 1;
}
-static struct xtables_target classify_target = {
- .family = NFPROTO_UNSPEC,
- .name = "CLASSIFY",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_classify_target_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)),
- .help = CLASSIFY_help,
- .print = CLASSIFY_print,
- .save = CLASSIFY_save,
- .x6_parse = CLASSIFY_parse,
- .x6_options = CLASSIFY_opts,
- .xlate = CLASSIFY_xlate,
+static struct xtables_target classify_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "CLASSIFY",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_classify_target_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)),
+ .help = CLASSIFY_help,
+ .print = CLASSIFY_print,
+ .save = CLASSIFY_save,
+ .x6_parse = CLASSIFY_parse,
+ .x6_options = CLASSIFY_opts,
+ .xlate = CLASSIFY_xlate,
+ },
+ {
+ .family = NFPROTO_ARP,
+ .name = "CLASSIFY",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_classify_target_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)),
+ .help = CLASSIFY_help,
+ .print = CLASSIFY_arp_print,
+ .save = CLASSIFY_arp_save,
+ .x6_parse = CLASSIFY_parse,
+ .x6_options = CLASSIFY_opts,
+ .xlate = CLASSIFY_xlate,
+ }
};
void _init(void)
{
- xtables_register_target(&classify_target);
+ xtables_register_targets(classify_tg_reg, ARRAY_SIZE(classify_tg_reg));
}
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index 43aa9779..b765af6c 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -1,3 +1,4 @@
+#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <xtables.h>
@@ -245,6 +246,87 @@ static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
printf(" --set-xmark 0x%x/0x%x", info->mark, info->mask);
}
+static void mark_tg_arp_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_mark_tginfo2 *info = (const void *)target->data;
+
+ if (info->mark == 0)
+ printf(" --and-mark %x", (unsigned int)(uint32_t)~info->mask);
+ else if (info->mark == info->mask)
+ printf(" --or-mark %x", info->mark);
+ else
+ printf(" --set-mark %x", info->mark);
+}
+
+static void mark_tg_arp_print(const void *ip,
+ const struct xt_entry_target *target, int numeric)
+{
+ mark_tg_arp_save(ip, target);
+}
+
+#define MARK_OPT 1
+#define AND_MARK_OPT 2
+#define OR_MARK_OPT 3
+
+static struct option mark_tg_arp_opts[] = {
+ { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT },
+ { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT },
+ { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT },
+ { .name = NULL}
+};
+
+static int
+mark_tg_arp_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct xt_mark_tginfo2 *info =
+ (struct xt_mark_tginfo2 *)(*target)->data;
+ int i;
+
+ switch (c) {
+ case MARK_OPT:
+ if (sscanf(argv[optind-1], "%x", &i) != 1) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad mark value `%s'", optarg);
+ return 0;
+ }
+ info->mark = i;
+ if (*flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "MARK: Can't specify --set-mark twice");
+ *flags = 1;
+ break;
+ case AND_MARK_OPT:
+ if (sscanf(argv[optind-1], "%x", &i) != 1) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad mark value `%s'", optarg);
+ return 0;
+ }
+ info->mark = 0;
+ info->mask = ~i;
+ if (*flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "MARK: Can't specify --and-mark twice");
+ *flags = 1;
+ break;
+ case OR_MARK_OPT:
+ if (sscanf(argv[optind-1], "%x", &i) != 1) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad mark value `%s'", optarg);
+ return 0;
+ }
+ info->mark = info->mask = i;
+ if (*flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "MARK: Can't specify --or-mark twice");
+ *flags = 1;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
static int mark_tg_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
@@ -335,6 +417,19 @@ static struct xtables_target mark_tg_reg[] = {
.x6_options = mark_tg_opts,
.xlate = mark_tg_xlate,
},
+ {
+ .version = XTABLES_VERSION,
+ .name = "MARK",
+ .revision = 2,
+ .family = NFPROTO_ARP,
+ .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
+ .help = mark_tg_help,
+ .print = mark_tg_arp_print,
+ .save = mark_tg_arp_save,
+ .parse = mark_tg_arp_parse,
+ .extra_opts = mark_tg_arp_opts,
+ },
};
void _init(void)
diff --git a/extensions/libxt_SYNPROXY.man b/extensions/libxt_SYNPROXY.man
index 25325fc2..30a71ed2 100644
--- a/extensions/libxt_SYNPROXY.man
+++ b/extensions/libxt_SYNPROXY.man
@@ -1,6 +1,8 @@
This target will process TCP three-way-handshake parallel in netfilter
context to protect either local or backend system. This target requires
connection tracking because sequence numbers need to be translated.
+The kernels ability to absorb SYNFLOOD was greatly improved starting with
+Linux 4.4, so this target should not be needed anymore to protect Linux servers.
.TP
\fB\-\-mss\fP \fImaximum segment size\fP
Maximum segment size announced to clients. This must match the backend.
diff --git a/extensions/libxt_TRACE.man b/extensions/libxt_TRACE.man
index 8d590a52..5187a8d2 100644
--- a/extensions/libxt_TRACE.man
+++ b/extensions/libxt_TRACE.man
@@ -1,13 +1,20 @@
This target marks packets so that the kernel will log every rule which match
-the packets as those traverse the tables, chains, rules.
+the packets as those traverse the tables, chains, rules. It can only be used in
+the
+.BR raw
+table.
.PP
-A logging backend, such as ip(6)t_LOG or nfnetlink_log, must be loaded for this
-to be visible.
+With iptables-legacy, a logging backend, such as ip(6)t_LOG or nfnetlink_log,
+must be loaded for this to be visible.
The packets are logged with the string prefix:
"TRACE: tablename:chainname:type:rulenum " where type can be "rule" for
plain rule, "return" for implicit rule at the end of a user defined chain
and "policy" for the policy of the built in chains.
-.br
-It can only be used in the
-.BR raw
-table.
+.PP
+With iptables-nft, the target is translated into nftables'
+.B "meta nftrace"
+expression. Hence the kernel sends trace events via netlink to userspace where
+they may be displayed using
+.B "xtables-monitor --trace"
+command. For details, refer to
+.BR xtables-monitor (8).
diff --git a/extensions/libxt_comment.t b/extensions/libxt_comment.t
index f12cd668..f0c8fb99 100644
--- a/extensions/libxt_comment.t
+++ b/extensions/libxt_comment.t
@@ -1,6 +1,8 @@
:INPUT,FORWARD,OUTPUT
-m comment;;FAIL
-m comment --comment;;FAIL
+-p tcp -m tcp --dport 22 -m comment --comment foo;=;OK
+-p tcp -m comment --comment foo -m tcp --dport 22;=;OK
#
# it fails with 256 characters
#
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index d06bb27a..5a01fe72 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -1,8 +1,10 @@
+#define _GNU_SOURCE
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter/xt_connlabel.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
@@ -32,40 +34,59 @@ static const struct xt_option_entry connlabel_mt_opts[] = {
/* cannot do this via _init, else static builds might spew error message
* for every iptables invocation.
*/
-static void connlabel_open(void)
+static int connlabel_open(void)
{
const char *fname;
if (map)
- return;
+ return 0;
map = nfct_labelmap_new(NULL);
if (map != NULL)
- return;
+ return 0;
fname = nfct_labels_get_path();
if (errno) {
- xtables_error(RESOURCE_PROBLEM,
- "cannot open %s: %s", fname, strerror(errno));
+ fprintf(stderr, "Warning: cannot open %s: %s\n",
+ fname, strerror(errno));
} else {
xtables_error(RESOURCE_PROBLEM,
"cannot parse %s: no labels found", fname);
}
+ return 1;
+}
+
+static int connlabel_value_parse(const char *in)
+{
+ char *end;
+ unsigned long value = strtoul(in, &end, 0);
+
+ if (in[0] == '\0' || *end != '\0')
+ return -1;
+
+ return value;
}
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
+ bool have_labelmap = !connlabel_open();
int tmp;
- connlabel_open();
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LABEL:
- tmp = nfct_labelmap_get_bit(map, cb->arg);
+ if (have_labelmap)
+ 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", cb->arg);
+ xtables_error(PARAMETER_PROBLEM,
+ "label '%s' not found or invalid value",
+ cb->arg);
+
info->bit = tmp;
if (cb->invert)
info->options |= XT_CONNLABEL_OP_INVERT;
@@ -81,7 +102,8 @@ static const char *connlabel_get_name(int b)
{
const char *name;
- connlabel_open();
+ if (connlabel_open())
+ return NULL;
name = nfct_labelmap_get_name(map, b);
if (name && strcmp(name, ""))
@@ -134,9 +156,13 @@ static int connlabel_mt_xlate(struct xt_xlate *xl,
const struct xt_connlabel_mtinfo *info =
(const void *)params->match->data;
const char *name = connlabel_get_name(info->bit);
+ char *valbuf = NULL;
- if (name == NULL)
- return 0;
+ if (name == NULL) {
+ if (asprintf(&valbuf, "%u", info->bit) < 0)
+ return 0;
+ name = valbuf;
+ }
if (info->options & XT_CONNLABEL_OP_SET)
xt_xlate_add(xl, "ct label set %s ", name);
@@ -146,6 +172,7 @@ static int connlabel_mt_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "and %s != ", name);
xt_xlate_add(xl, "%s", name);
+ free(valbuf);
return 1;
}
diff --git a/extensions/libxt_connlabel.t b/extensions/libxt_connlabel.t
index aad1032b..7265bd47 100644
--- a/extensions/libxt_connlabel.t
+++ b/extensions/libxt_connlabel.t
@@ -1,18 +1,7 @@
:INPUT,FORWARD,OUTPUT
-# Backup the connlabel.conf, then add some label maps for test
-@[ -f /etc/xtables/connlabel.conf ] && mv /etc/xtables/connlabel.conf /tmp/connlabel.conf.bak
-@mkdir -p /etc/xtables
-@echo "40 bit40" > /etc/xtables/connlabel.conf
-@echo "41 bit41" >> /etc/xtables/connlabel.conf
-@echo "128 bit128" >> /etc/xtables/connlabel.conf
--m connlabel --label "bit40";=;OK
--m connlabel ! --label "bit40";=;OK
--m connlabel --label "bit41" --set;=;OK
--m connlabel ! --label "bit41" --set;=;OK
--m connlabel --label "bit128";;FAIL
-@echo > /etc/xtables/connlabel.conf
--m connlabel --label "abc";;FAIL
-@rm -f /etc/xtables/connlabel.conf
--m connlabel --label "abc";;FAIL
-# Restore the original connlabel.conf
-@[ -f /tmp/connlabel.conf.bak ] && mv /tmp/connlabel.conf.bak /etc/xtables/connlabel.conf
+-m connlabel --label "40";=;OK
+-m connlabel ! --label "40";=;OK
+-m connlabel --label "41" --set;=;OK
+-m connlabel ! --label "41" --set;=;OK
+-m connlabel --label "2048";;FAIL
+-m connlabel --label "foobar_not_there";;FAIL
diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate
index 5be42204..12e4ac03 100644
--- a/extensions/libxt_connlabel.txlate
+++ b/extensions/libxt_connlabel.txlate
@@ -1,5 +1,5 @@
-iptables-translate -A INPUT -m connlabel --label bit40
-nft add rule ip filter INPUT ct label bit40 counter
+iptables-translate -A INPUT -m connlabel --label 40
+nft add rule ip filter INPUT ct label 40 counter
-iptables-translate -A INPUT -m connlabel ! --label bit40 --set
-nft add rule ip filter INPUT ct label set bit40 ct label and bit40 != bit40 counter
+iptables-translate -A INPUT -m connlabel ! --label 40 --set
+nft add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter
diff --git a/extensions/libxt_ipvs.c b/extensions/libxt_ipvs.c
index a6c57a03..51952be4 100644
--- a/extensions/libxt_ipvs.c
+++ b/extensions/libxt_ipvs.c
@@ -27,7 +27,7 @@ enum {
static const struct xt_option_entry ipvs_mt_opts[] = {
{.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE,
.flags = XTOPT_INVERT},
- {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_STRING,
+ {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_PROTOCOL,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)},
{.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_INVERT},
@@ -69,9 +69,6 @@ static void ipvs_mt_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
- case O_VPROTO:
- data->l4proto = cb->val.protocol;
- break;
case O_VADDR:
memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr));
memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask));
@@ -168,7 +165,7 @@ static void ipvs_mt_dump(const void *ip, const struct xt_ipvs_mtinfo *data,
if (data->bitmask & XT_IPVS_PROTO) {
if (data->invert & XT_IPVS_PROTO)
printf(" !");
- printf(" %sproto %u", prefix, data->l4proto);
+ printf(" %svproto %u", prefix, data->l4proto);
}
if (data->bitmask & XT_IPVS_VADDR) {
diff --git a/extensions/libxt_ipvs.t b/extensions/libxt_ipvs.t
new file mode 100644
index 00000000..c2acc666
--- /dev/null
+++ b/extensions/libxt_ipvs.t
@@ -0,0 +1,20 @@
+:INPUT,FORWARD,OUTPUT
+-m ipvs --ipvs;=;OK
+-m ipvs ! --ipvs;=;OK
+-m ipvs --vproto tcp;-m ipvs --vproto 6;OK
+-m ipvs ! --vproto TCP;-m ipvs ! --vproto 6;OK
+-m ipvs --vproto 23;=;OK
+-m ipvs --vaddr 1.2.3.4;=;OK
+-m ipvs ! --vaddr 1.2.3.4/255.255.255.0;-m ipvs ! --vaddr 1.2.3.4/24;OK
+-m ipvs --vport http;-m ipvs --vport 80;OK
+-m ipvs ! --vport ssh;-m ipvs ! --vport 22;OK
+-m ipvs --vport 22;=;OK
+-m ipvs ! --vport 443;=;OK
+-m ipvs --vdir ORIGINAL;=;OK
+-m ipvs --vdir REPLY;=;OK
+-m ipvs --vmethod GATE;=;OK
+-m ipvs ! --vmethod IPIP;=;OK
+-m ipvs --vmethod MASQ;=;OK
+-m ipvs --vportctl 21;=;OK
+-m ipvs ! --vportctl 21;=;OK
+-m ipvs --vproto 6 --vaddr 1.2.3.4/16 --vport 22 --vdir ORIGINAL --vmethod GATE;=;OK
diff --git a/extensions/libxt_osf.man b/extensions/libxt_osf.man
index f3a85fb0..5ba92ce0 100644
--- a/extensions/libxt_osf.man
+++ b/extensions/libxt_osf.man
@@ -41,5 +41,5 @@ To remove them again,
.PP
\fBnfnl_osf -f /usr/share/xtables/pf.os -d\fP
.PP
-The fingerprint database can be downlaoded from
+The fingerprint database can be downloaded from
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os .
diff --git a/include/libiptc/xtcshared.h b/include/libiptc/xtcshared.h
index 773ebc4c..341f9d4f 100644
--- a/include/libiptc/xtcshared.h
+++ b/include/libiptc/xtcshared.h
@@ -7,11 +7,16 @@ struct xt_counters;
struct xtc_ops {
int (*commit)(struct xtc_handle *);
+ struct xtc_handle *(*init)(const char *);
void (*free)(struct xtc_handle *);
int (*builtin)(const char *, struct xtc_handle *const);
int (*is_chain)(const char *, struct xtc_handle *const);
int (*flush_entries)(const xt_chainlabel, struct xtc_handle *);
int (*create_chain)(const xt_chainlabel, struct xtc_handle *);
+ const char *(*first_chain)(struct xtc_handle *);
+ const char *(*next_chain)(struct xtc_handle *);
+ const char *(*get_policy)(const char *, struct xt_counters *,
+ struct xtc_handle *);
int (*set_policy)(const xt_chainlabel, const xt_chainlabel,
struct xt_counters *, struct xtc_handle *);
const char *(*strerror)(int);
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index c3f087ac..042d8b14 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -3,8 +3,10 @@
#include <linux/types.h>
+#ifndef _NETINET_IN_H
#include <linux/in.h>
#include <linux/in6.h>
+#endif
#include <limits.h>
/* Responses from hook functions. */
diff --git a/iptables/.gitignore b/iptables/.gitignore
index d0301c6d..c638139b 100644
--- a/iptables/.gitignore
+++ b/iptables/.gitignore
@@ -2,6 +2,7 @@
/ip6tables-save
/ip6tables-restore
/ip6tables-static
+/ip6tables-translate.8
/iptables
/iptables.8
/iptables-extensions.8
@@ -11,6 +12,7 @@
/iptables-restore
/iptables-restore.8
/iptables-static
+/iptables-translate.8
/iptables-xml
/iptables-xml.1
/xtables-multi
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 581dc32b..3ff85893 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -13,18 +13,16 @@ if ENABLE_STATIC
xtables_legacy_multi_CFLAGS += -DALL_INCLUSIVE
endif
if ENABLE_IPV4
-xtables_legacy_multi_SOURCES += iptables-save.c iptables-restore.c \
- iptables-standalone.c iptables.c
+xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c
xtables_legacy_multi_CFLAGS += -DENABLE_IPV4
xtables_legacy_multi_LDADD += ../libiptc/libip4tc.la ../extensions/libext4.a
endif
if ENABLE_IPV6
-xtables_legacy_multi_SOURCES += ip6tables-save.c ip6tables-restore.c \
- ip6tables-standalone.c ip6tables.c
+xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c
xtables_legacy_multi_CFLAGS += -DENABLE_IPV6
xtables_legacy_multi_LDADD += ../libiptc/libip6tc.la ../extensions/libext6.a
endif
-xtables_legacy_multi_SOURCES += xshared.c
+xtables_legacy_multi_SOURCES += xshared.c iptables-restore.c iptables-save.c
xtables_legacy_multi_LDADD += ../libxtables/libxtables.la -lm
# iptables using nf_tables api
@@ -62,8 +60,14 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
iptables-xml.1 ip6tables.8 ip6tables-restore.8 \
ip6tables-save.8 iptables-extensions.8 \
xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
+ iptables-translate.8 ip6tables-translate.8 \
xtables-monitor.8
+if ENABLE_NFTABLES
+man_MANS += arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \
+ ebtables-nft.8
+endif
CLEANFILES = iptables.8 xtables-monitor.8 \
+ iptables-translate.8 ip6tables-translate.8 \
xtables-config-parser.c xtables-config-syntax.c
vx_bin_links = iptables-xml
@@ -94,6 +98,9 @@ iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../e
-e '/@MATCH@/ r ../extensions/matches.man' \
-e '/@TARGET@/ r ../extensions/targets.man' $< >$@;
+iptables-translate.8 ip6tables-translate.8:
+ ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@
+
pkgconfig_DATA = xtables.pc
# Using if..fi avoids an ugly "error (ignored)" message :)
diff --git a/iptables/arptables-nft-restore.8 b/iptables/arptables-nft-restore.8
new file mode 100644
index 00000000..09d9082c
--- /dev/null
+++ b/iptables/arptables-nft-restore.8
@@ -0,0 +1,39 @@
+.TH ARPTABLES-RESTORE 8 "March 2019" "" ""
+.\"
+.\" Man page written by Jesper Dangaard Brouer <brouer@redhat.com> based on a
+.\" Man page written by Harald Welte <laforge@gnumonks.org>
+.\" It is based on the iptables-restore man page.
+.\"
+.\" 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 program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.SH NAME
+arptables-restore \- Restore ARP Tables (nft-based)
+.SH SYNOPSIS
+\fBarptables\-restore
+.SH DESCRIPTION
+.PP
+.B arptables-restore
+is used to restore ARP Tables from data specified on STDIN or
+via a file as first argument.
+Use I/O redirection provided by your shell to read from a file
+.TP
+.B arptables-restore
+flushes (deletes) all previous contents of the respective ARP Table.
+.SH AUTHOR
+Jesper Dangaard Brouer <brouer@redhat.com>
+.SH SEE ALSO
+\fBarptables\-save\fP(8), \fBarptables\fP(8)
+.PP
diff --git a/iptables/arptables-nft-save.8 b/iptables/arptables-nft-save.8
new file mode 100644
index 00000000..905e5985
--- /dev/null
+++ b/iptables/arptables-nft-save.8
@@ -0,0 +1,47 @@
+.TH ARPTABLES-SAVE 8 "March 2019" "" ""
+.\"
+.\" Man page written by Jesper Dangaard Brouer <brouer@redhat.com> based on a
+.\" Man page written by Harald Welte <laforge@gnumonks.org>
+.\" It is based on the iptables-save man page.
+.\"
+.\" 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 program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.SH NAME
+arptables-save \- dump arptables rules to stdout (nft-based)
+.SH SYNOPSIS
+\fBarptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
+.P
+\fBarptables\-save\fP [\fB\-V\fP]
+.SH DESCRIPTION
+.PP
+.B arptables-save
+is used to dump the contents of an ARP Table in easily parseable format
+to STDOUT. Use I/O-redirection provided by your shell to write to a file.
+.TP
+\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP
+Specify the path to the modprobe program. By default, arptables-save will
+inspect /proc/sys/kernel/modprobe to determine the executable's path.
+.TP
+\fB\-c\fR, \fB\-\-counters\fR
+Include the current values of all packet and byte counters in the output.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Print version information and exit.
+.SH AUTHOR
+Jesper Dangaard Brouer <brouer@redhat.com>
+.SH SEE ALSO
+\fBarptables\-restore\fP(8), \fBarptables\fP(8)
+.PP
diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8
new file mode 100644
index 00000000..ea31e084
--- /dev/null
+++ b/iptables/arptables-nft.8
@@ -0,0 +1,348 @@
+.TH ARPTABLES 8 "March 2019"
+.\"
+.\" Man page originally written by Jochen Friedrich <jochen@scram.de>,
+.\" maintained by Bart De Schuymer.
+.\" It is based on the iptables man page.
+.\"
+.\" Iptables page by Herve Eychenne March 2000.
+.\"
+.\" 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 program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.SH NAME
+arptables \- ARP table administration (nft-based)
+.SH SYNOPSIS
+.BR "arptables " [ "-t table" ] " -" [ AD ] " chain rule-specification " [ options ]
+.br
+.BR "arptables " [ "-t table" ] " -" [ RI ] " chain rulenum rule-specification " [ options ]
+.br
+.BR "arptables " [ "-t table" ] " -D chain rulenum " [ options ]
+.br
+.BR "arptables " [ "-t table" ] " -" [ "LFZ" ] " " [ chain ] " " [ options ]
+.br
+.BR "arptables " [ "-t table" ] " -" [ "NX" ] " chain"
+.br
+.BR "arptables " [ "-t table" ] " -E old-chain-name new-chain-name"
+.br
+.BR "arptables " [ "-t table" ] " -P chain target " [ options ]
+
+.SH DESCRIPTION
+.B arptables
+is a user space tool, it is used to set up and maintain the
+tables of ARP rules in the Linux kernel. These rules inspect
+the ARP frames which they see.
+.B arptables
+is analogous to the
+.B iptables
+user space tool, but
+.B arptables
+is less complicated.
+
+.SS CHAINS
+The kernel table is used to divide functionality into
+different sets of rules. Each set of rules is called a chain.
+Each chain is an ordered list of rules that can match ARP frames. If a
+rule matches an ARP frame, then a processing specification tells
+what to do with that matching frame. The processing specification is
+called a 'target'. However, if the frame does not match the current
+rule in the chain, then the next rule in the chain is examined and so forth.
+The user can create new (user-defined) chains which can be used as the 'target' of a rule.
+
+.SS TARGETS
+A firewall rule specifies criteria for an ARP frame and a frame
+processing specification called a target. When a frame matches a rule,
+then the next action performed by the kernel is specified by the target.
+The target can be one of these values:
+.IR ACCEPT ,
+.IR DROP ,
+.IR CONTINUE ,
+.IR RETURN ,
+an 'extension' (see below) or a user-defined chain.
+.PP
+.I ACCEPT
+means to let the frame through.
+.I DROP
+means the frame has to be dropped.
+.I CONTINUE
+means the next rule has to be checked. This can be handy to know how many
+frames pass a certain point in the chain or to log those frames.
+.I RETURN
+means stop traversing this chain and resume at the next rule in the
+previous (calling) chain.
+For the extension targets please see the
+.B "TARGET EXTENSIONS"
+section of this man page.
+.SS TABLES
+There is only one ARP table in the Linux
+kernel. The table is
+.BR filter.
+You can drop the '-t filter' argument to the arptables command.
+The -t argument must be the
+first argument on the arptables command line, if used.
+.TP
+.B "-t, --table"
+.br
+.BR filter ,
+is the only table and contains two built-in chains:
+.B INPUT
+(for frames destined for the host) and
+.B OUTPUT
+(for locally-generated frames).
+.br
+.br
+.SH ARPTABLES COMMAND LINE ARGUMENTS
+After the initial arptables command line argument, the remaining
+arguments can be divided into several different groups. These groups
+are commands, miscellaneous commands, rule-specifications, match-extensions,
+and watcher-extensions.
+.SS COMMANDS
+The arptables command arguments specify the actions to perform on the table
+defined with the -t argument. If you do not use the -t argument to name
+a table, the commands apply to the default filter table.
+With the exception of the
+.B "-Z"
+command, only one command may be used on the command line at a time.
+.TP
+.B "-A, --append"
+Append a rule to the end of the selected chain.
+.TP
+.B "-D, --delete"
+Delete the specified rule from the selected chain. There are two ways to
+use this command. The first is by specifying an interval of rule numbers
+to delete, syntax: start_nr[:end_nr]. Using negative numbers is allowed, for more
+details about using negative numbers, see the -I command. The second usage is by
+specifying the complete rule as it would have been specified when it was added.
+.TP
+.B "-I, --insert"
+Insert the specified rule into the selected chain at the specified rule number.
+If the current number of rules equals N, then the specified number can be
+between -N and N+1. For a positive number i, it holds that i and i-N-1 specify the
+same place in the chain where the rule should be inserted. The number 0 specifies
+the place past the last rule in the chain and using this number is therefore
+equivalent with using the -A command.
+.TP
+.B "-R, --replace"
+Replaces the specified rule into the selected chain at the specified rule number.
+If the current number of rules equals N, then the specified number can be
+between 1 and N. i specifies the place in the chain where the rule should be replaced.
+.TP
+.B "-P, --policy"
+Set the policy for the chain to the given target. The policy can be
+.BR ACCEPT ", " DROP " or " RETURN .
+.TP
+.B "-F, --flush"
+Flush the selected chain. If no chain is selected, then every chain will be
+flushed. Flushing the chain does not change the policy of the
+chain, however.
+.TP
+.B "-Z, --zero"
+Set the counters of the selected chain to zero. If no chain is selected, all the counters
+are set to zero. The
+.B "-Z"
+command can be used in conjunction with the
+.B "-L"
+command.
+When both the
+.B "-Z"
+and
+.B "-L"
+commands are used together in this way, the rule counters are printed on the screen
+before they are set to zero.
+.TP
+.B "-L, --list"
+List all rules in the selected chain. If no chain is selected, all chains
+are listed.
+.TP
+.B "-N, --new-chain"
+Create a new user-defined chain with the given name. The number of
+user-defined chains is unlimited. A user-defined chain name has maximum
+length of 31 characters.
+.TP
+.B "-X, --delete-chain"
+Delete the specified user-defined chain. There must be no remaining references
+to the specified chain, otherwise
+.B arptables
+will refuse to delete it. If no chain is specified, all user-defined
+chains that aren't referenced will be removed.
+.TP
+.B "-E, --rename-chain"
+Rename the specified chain to a new name. Besides renaming a user-defined
+chain, you may rename a standard chain name to a name that suits your
+taste. For example, if you like PREBRIDGING more than PREROUTING,
+then you can use the -E command to rename the PREROUTING chain. If you do
+rename one of the standard
+.B arptables
+chain names, please be sure to mention
+this fact should you post a question on the
+.B arptables
+mailing lists.
+It would be wise to use the standard name in your post. Renaming a standard
+.B arptables
+chain in this fashion has no effect on the structure or function
+of the
+.B arptables
+kernel table.
+
+.SS MISCELLANOUS COMMANDS
+.TP
+.B "-V, --version"
+Show the version of the arptables userspace program.
+.TP
+.B "-h, --help"
+Give a brief description of the command syntax.
+.TP
+.BR "-j, --jump " "\fItarget\fP"
+The target of the rule. This is one of the following values:
+.BR ACCEPT ,
+.BR DROP ,
+.BR CONTINUE ,
+.BR RETURN ,
+a target extension (see
+.BR "TARGET EXTENSIONS" ")"
+or a user-defined chain name.
+.TP
+.BI "-c, --set-counters " "PKTS BYTES"
+This enables the administrator to initialize the packet and byte
+counters of a rule (during
+.B INSERT,
+.B APPEND,
+.B REPLACE
+operations).
+
+.SS RULE-SPECIFICATIONS
+The following command line arguments make up a rule specification (as used
+in the add and delete commands). A "!" option before the specification
+inverts the test for that specification. Apart from these standard rule
+specifications there are some other command line arguments of interest.
+.TP
+.BR "-s, --source-ip " "[!] \fIaddress\fP[/\fImask]\fP"
+The Source IP specification.
+.TP
+.BR "-d, --destination-ip " "[!] \fIaddress\fP[/\fImask]\fP"
+The Destination IP specification.
+.TP
+.BR "--source-mac " "[!] \fIaddress\fP[/\fImask\fP]"
+The source mac address. Both mask and address are written as 6 hexadecimal
+numbers separated by colons.
+.TP
+.BR "--destination-mac " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination mac address. Both mask and address are written as 6 hexadecimal
+numbers separated by colons.
+.TP
+.BR "-i, --in-interface " "[!] \fIname\fP"
+The interface via which a frame is received (for the
+.B INPUT
+chain). The flag
+.B --in-if
+is an alias for this option.
+.TP
+.BR "-o, --out-interface " "[!] \fIname\fP"
+The interface via which a frame is going to be sent (for the
+.B OUTPUT
+chain). The flag
+.B --out-if
+is an alias for this option.
+.TP
+.BR "-l, --h-length " "\fIlength\fP[/\fImask\fP]"
+The hardware length (nr of bytes)
+.TP
+.BR "--opcode " "\fIcode\fP[/\fImask\fP]
+The operation code (2 bytes). Available values are:
+.BR 1 = Request
+.BR 2 = Reply
+.BR 3 = Request_Reverse
+.BR 4 = Reply_Reverse
+.BR 5 = DRARP_Request
+.BR 6 = DRARP_Reply
+.BR 7 = DRARP_Error
+.BR 8 = InARP_Request
+.BR 9 = ARP_NAK .
+.TP
+.BR "--h-type " "\fItype\fP[/\fImask\fP]"
+The hardware type (2 bytes, hexadecimal). Available values are:
+.BR 1 = Ethernet .
+.TP
+.BR "--proto-type " "\fItype\fP[/\fImask\fP]"
+The protocol type (2 bytes). Available values are:
+.BR 0x800 = IPv4 .
+
+.SS TARGET-EXTENSIONS
+.B arptables
+extensions are precompiled into the userspace tool. So there is no need
+to explicitly load them with a -m option like in
+.BR iptables .
+However, these
+extensions deal with functionality supported by supplemental kernel modules.
+.SS mangle
+.TP
+.BR "--mangle-ip-s IP address"
+Mangles Source IP Address to given value.
+.TP
+.BR "--mangle-ip-d IP address"
+Mangles Destination IP Address to given value.
+.TP
+.BR "--mangle-mac-s MAC address"
+Mangles Source MAC Address to given value.
+.TP
+.BR "--mangle-mac-d MAC address"
+Mangles Destination MAC Address to given value.
+.TP
+.BR "--mangle-target target "
+Target of ARP mangle operation
+.BR "" ( DROP ", " CONTINUE " or " ACCEPT " -- default is " ACCEPT ).
+.SS CLASSIFY
+This module allows you to set the skb->priority value (and thus clas-
+sify the packet into a specific CBQ class).
+
+.TP
+.BR "--set-class major:minor"
+
+Set the major and minor class value. The values are always
+interpreted as hexadecimal even if no 0x prefix is given.
+
+.SS MARK
+This module allows you to set the skb->mark value (and thus classify
+the packet by the mark in u32)
+
+.TP
+.BR "--set-mark mark"
+Set the mark value. The values are always
+interpreted as hexadecimal even if no 0x prefix is given
+
+.TP
+.BR "--and-mark mark"
+Binary AND the mark with bits.
+
+.TP
+.BR "--or-mark mark"
+Binary OR the mark with bits.
+
+.SH NOTES
+In this nft-based version of
+.BR arptables ,
+support for
+.B FORWARD
+chain has not been implemented. Since ARP packets are "forwarded" only by Linux
+bridges, the same may be achieved using
+.B FORWARD
+chain in
+.BR ebtables .
+
+.SH MAILINGLISTS
+.BR "" "See " http://netfilter.org/mailinglists.html
+.SH SEE ALSO
+.BR xtables-nft "(8), " iptables "(8), " ebtables "(8), " ip (8)
+.PP
+.BR "" "See " https://wiki.nftables.org
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
new file mode 100644
index 00000000..db8b2ab2
--- /dev/null
+++ b/iptables/ebtables-nft.8
@@ -0,0 +1,1116 @@
+.TH EBTABLES 8 "December 2011"
+.\"
+.\" Man page written by Bart De Schuymer <bdschuym@pandora.be>
+.\" It is based on the iptables man page.
+.\"
+.\" The man page was edited, February 25th 2003, by
+.\" Greg Morgan <" dr_kludge_at_users_sourceforge_net >
+.\"
+.\" Iptables page by Herve Eychenne March 2000.
+.\"
+.\" 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 program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.SH NAME
+ebtables \- Ethernet bridge frame table administration (nft-based)
+.SH SYNOPSIS
+.BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target"
+.br
+.BR "ebtables " [ -t " table ] " -P " chain " ACCEPT " | " DROP " | " RETURN
+.br
+.BR "ebtables " [ -t " table ] " -F " [chain]"
+.br
+.BR "ebtables " [ -t " table ] " -Z " [chain]"
+.br
+.BR "ebtables " [ -t " table ] " -L " [" -Z "] [chain] [ [" --Ln "] | [" --Lx "] ] [" --Lc "] [" --Lmac2 ]
+.br
+.BR "ebtables " [ -t " table ] " -N " chain [" "-P ACCEPT " | " DROP " | " RETURN" ]
+.br
+.BR "ebtables " [ -t " table ] " -X " [chain]"
+.br
+.BR "ebtables " [ -t " table ] " -E " old-chain-name new-chain-name"
+.br
+.BR "ebtables " [ -t " table ] " --init-table
+.br
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit
+.br
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init
+.br
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
+.br
+
+.SH DESCRIPTION
+.B ebtables
+is an application program used to set up and maintain the
+tables of rules (inside the Linux kernel) that inspect
+Ethernet frames.
+It is analogous to the
+.B iptables
+application, but less complicated, due to the fact that the Ethernet protocol
+is much simpler than the IP protocol.
+.SS CHAINS
+There are two ebtables tables with built-in chains in the
+Linux kernel. These tables are used to divide functionality into
+different sets of rules. Each set of rules is called a chain.
+Each chain is an ordered list of rules that can match Ethernet frames. If a
+rule matches an Ethernet frame, then a processing specification tells
+what to do with that matching frame. The processing specification is
+called a 'target'. However, if the frame does not match the current
+rule in the chain, then the next rule in the chain is examined and so forth.
+The user can create new (user-defined) chains that can be used as the 'target'
+of a rule. User-defined chains are very useful to get better performance
+over the linear traversal of the rules and are also essential for structuring
+the filtering rules into well-organized and maintainable sets of rules.
+.SS TARGETS
+A firewall rule specifies criteria for an Ethernet frame and a frame
+processing specification called a target. When a frame matches a rule,
+then the next action performed by the kernel is specified by the target.
+The target can be one of these values:
+.BR ACCEPT ,
+.BR DROP ,
+.BR CONTINUE ,
+.BR RETURN ,
+an 'extension' (see below) or a jump to a user-defined chain.
+.PP
+.B ACCEPT
+means to let the frame through.
+.B DROP
+means the frame has to be dropped.
+.B CONTINUE
+means the next rule has to be checked. This can be handy, f.e., to know how many
+frames pass a certain point in the chain, to log those frames or to apply multiple
+targets on a frame.
+.B RETURN
+means stop traversing this chain and resume at the next rule in the
+previous (calling) chain.
+For the extension targets please refer to the
+.B "TARGET EXTENSIONS"
+section of this man page.
+.SS TABLES
+As stated earlier, there are two ebtables tables in the Linux
+kernel. The table names are
+.BR filter " and " nat .
+Of these two tables,
+the filter table is the default table that the command operates on.
+If you are working with the filter table, then you can drop the '-t filter'
+argument to the ebtables command. However, you will need to provide
+the -t argument for
+.B nat
+table. Moreover, the -t argument must be the
+first argument on the ebtables command line, if used.
+.TP
+.B "-t, --table"
+.br
+.B filter
+is the default table and contains three built-in chains:
+.B INPUT
+(for frames destined for the bridge itself, on the level of the MAC destination address),
+.B OUTPUT
+(for locally-generated or (b)routed frames) and
+.B FORWARD
+(for frames being forwarded by the bridge).
+.br
+.br
+.B nat
+is mostly used to change the mac addresses and contains three built-in chains:
+.B PREROUTING
+(for altering frames as soon as they come in),
+.B OUTPUT
+(for altering locally generated or (b)routed frames before they are bridged) and
+.B POSTROUTING
+(for altering frames as they are about to go out). A small note on the naming
+of chains PREROUTING and POSTROUTING: it would be more accurate to call them
+PREFORWARDING and POSTFORWARDING, but for all those who come from the
+iptables world to ebtables it is easier to have the same names. Note that you
+can change the name
+.BR "" ( -E )
+if you don't like the default.
+.SH EBTABLES COMMAND LINE ARGUMENTS
+After the initial ebtables '-t table' command line argument, the remaining
+arguments can be divided into several groups. These groups
+are commands, miscellaneous commands, rule specifications, match extensions,
+watcher extensions and target extensions.
+.SS COMMANDS
+The ebtables command arguments specify the actions to perform on the table
+defined with the -t argument. If you do not use the -t argument to name
+a table, the commands apply to the default filter table.
+Only one command may be used on the command line at a time, except when
+the commands
+.BR -L " and " -Z
+are combined, the commands
+.BR -N " and " -P
+are combined, or when
+.B --atomic-file
+is used.
+.TP
+.B "-A, --append"
+Append a rule to the end of the selected chain.
+.TP
+.B "-D, --delete"
+Delete the specified rule or rules from the selected chain. There are two ways to
+use this command. The first is by specifying an interval of rule numbers
+to delete (directly after
+.BR -D ).
+Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use
+.B -L --Ln
+to list the rules with their rule number). When \fIend_nr\fP is omitted, all rules starting
+from \fIstart_nr\fP are deleted. Using negative numbers is allowed, for more
+details about using negative numbers, see the
+.B -I
+command. The second usage is by
+specifying the complete rule as it would have been specified when it was added. Only
+the first encountered rule that is the same as this specified rule, in other
+words the matching rule with the lowest (positive) rule number, is deleted.
+.TP
+.B "-C, --change-counters"
+Change the counters of the specified rule or rules from the selected chain. There are two ways to
+use this command. The first is by specifying an interval of rule numbers
+to do the changes on (directly after
+.BR -C ).
+Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use
+.B -L --Ln
+to list the rules with their rule number). The details are the same as for the
+.BR -D " command. The second usage is by"
+specifying the complete rule as it would have been specified when it was added. Only
+the counters of the first encountered rule that is the same as this specified rule, in other
+words the matching rule with the lowest (positive) rule number, are changed.
+In the first usage, the counters are specified directly after the interval specification,
+in the second usage directly after
+.BR -C .
+First the packet counter is specified, then the byte counter. If the specified counters start
+with a '+', the counter values are added to the respective current counter values.
+If the specified counters start with a '-', the counter values are decreased from the respective
+current counter values. No bounds checking is done. If the counters don't start with '+' or '-',
+the current counters are changed to the specified counters.
+.TP
+.B "-I, --insert"
+Insert the specified rule into the selected chain at the specified rule number. If the
+rule number is not specified, the rule is added at the head of the chain.
+If the current number of rules equals
+.IR N ,
+then the specified number can be
+between
+.IR -N " and " N+1 .
+For a positive number
+.IR i ,
+it holds that
+.IR i " and " i-N-1
+specify the same place in the chain where the rule should be inserted. The rule number
+0 specifies the place past the last rule in the chain and using this number is therefore
+equivalent to using the
+.BR -A " command."
+Rule numbers structly smaller than 0 can be useful when more than one rule needs to be inserted
+in a chain.
+.TP
+.B "-P, --policy"
+Set the policy for the chain to the given target. The policy can be
+.BR ACCEPT ", " DROP " or " RETURN .
+.TP
+.B "-F, --flush"
+Flush the selected chain. If no chain is selected, then every chain will be
+flushed. Flushing a chain does not change the policy of the
+chain, however.
+.TP
+.B "-Z, --zero"
+Set the counters of the selected chain to zero. If no chain is selected, all the counters
+are set to zero. The
+.B "-Z"
+command can be used in conjunction with the
+.B "-L"
+command.
+When both the
+.B "-Z"
+and
+.B "-L"
+commands are used together in this way, the rule counters are printed on the screen
+before they are set to zero.
+.TP
+.B "-L, --list"
+List all rules in the selected chain. If no chain is selected, all chains
+are listed.
+.br
+The following options change the output of the
+.B "-L"
+command.
+.br
+.B "--Ln"
+.br
+Places the rule number in front of every rule. This option is incompatible with the
+.BR --Lx " option."
+.br
+.B "--Lc"
+.br
+Shows the counters at the end of each rule displayed by the
+.B "-L"
+command. Both a frame counter (pcnt) and a byte counter (bcnt) are displayed.
+The frame counter shows how many frames have matched the specific rule, the byte
+counter shows the sum of the frame sizes of these matching frames. Using this option
+.BR "" "in combination with the " --Lx " option causes the counters to be written out"
+.BR "" "in the '" -c " <pcnt> <bcnt>' option format."
+.br
+.B "--Lx"
+.br
+Changes the output so that it produces a set of ebtables commands that construct
+the contents of the chain, when specified.
+If no chain is specified, ebtables commands to construct the contents of the
+table are given, including commands for creating the user-defined chains (if any).
+You can use this set of commands in an ebtables boot or reload
+script. For example the output could be used at system startup.
+The
+.B "--Lx"
+option is incompatible with the
+.B "--Ln"
+listing option. Using the
+.BR --Lx " option together with the " --Lc " option will cause the counters to be written out"
+.BR "" "in the '" -c " <pcnt> <bcnt>' option format."
+.br
+.B "--Lmac2"
+.br
+Shows all MAC addresses with the same length, adding leading zeroes
+if necessary. The default representation omits leading zeroes in the addresses.
+.TP
+.B "-N, --new-chain"
+Create a new user-defined chain with the given name. The number of
+user-defined chains is limited only by the number of possible chain names.
+A user-defined chain name has a maximum
+length of 31 characters. The standard policy of the user-defined chain is
+ACCEPT. The policy of the new chain can be initialized to a different standard
+target by using the
+.B -P
+command together with the
+.B -N
+command. In this case, the chain name does not have to be specified for the
+.B -P
+command.
+.TP
+.B "-X, --delete-chain"
+Delete the specified user-defined chain. There must be no remaining references (jumps)
+to the specified chain, otherwise ebtables will refuse to delete it. If no chain is
+specified, all user-defined chains that aren't referenced will be removed.
+.TP
+.B "-E, --rename-chain"
+Rename the specified chain to a new name. Besides renaming a user-defined
+chain, you can rename a standard chain to a name that suits your
+taste. For example, if you like PREFORWARDING more than PREROUTING,
+then you can use the -E command to rename the PREROUTING chain. If you do
+rename one of the standard ebtables chain names, please be sure to mention
+this fact should you post a question on the ebtables mailing lists.
+It would be wise to use the standard name in your post. Renaming a standard
+ebtables chain in this fashion has no effect on the structure or functioning
+of the ebtables kernel table.
+.TP
+.B "--init-table"
+Replace the current table data by the initial table data.
+.TP
+.B "--atomic-init"
+Copy the kernel's initial data of the table to the specified
+file. This can be used as the first action, after which rules are added
+to the file. The file can be specified using the
+.B --atomic-file
+command or through the
+.IR EBTABLES_ATOMIC_FILE " environment variable."
+.TP
+.B "--atomic-save"
+Copy the kernel's current data of the table to the specified
+file. This can be used as the first action, after which rules are added
+to the file. The file can be specified using the
+.B --atomic-file
+command or through the
+.IR EBTABLES_ATOMIC_FILE " environment variable."
+.TP
+.B "--atomic-commit"
+Replace the kernel table data with the data contained in the specified
+file. This is a useful command that allows you to load all your rules of a
+certain table into the kernel at once, saving the kernel a lot of precious
+time and allowing atomic updates of the tables. The file which contains
+the table data is constructed by using either the
+.B "--atomic-init"
+or the
+.B "--atomic-save"
+command to generate a starting file. After that, using the
+.B "--atomic-file"
+command when constructing rules or setting the
+.IR EBTABLES_ATOMIC_FILE " environment variable"
+allows you to extend the file and build the complete table before
+committing it to the kernel. This command can be very useful in boot scripts
+to populate the ebtables tables in a fast way.
+.SS MISCELLANOUS COMMANDS
+.TP
+.B "-V, --version"
+Show the version of the ebtables userspace program.
+.TP
+.BR "-h, --help " "[\fIlist of module names\fP]"
+Give a brief description of the command syntax. Here you can also specify
+names of extensions and ebtables will try to write help about those
+extensions. E.g.
+.IR "ebtables -h snat log ip arp" .
+Specify
+.I list_extensions
+to list all extensions supported by the userspace
+utility.
+.TP
+.BR "-j, --jump " "\fItarget\fP"
+The target of the rule. This is one of the following values:
+.BR ACCEPT ,
+.BR DROP ,
+.BR CONTINUE ,
+.BR RETURN ,
+a target extension (see
+.BR "TARGET EXTENSIONS" ")"
+or a user-defined chain name.
+.TP
+.B --atomic-file "\fIfile\fP"
+Let the command operate on the specified
+.IR file .
+The data of the table to
+operate on will be extracted from the file and the result of the operation
+will be saved back into the file. If specified, this option should come
+before the command specification. An alternative that should be preferred,
+is setting the
+.IR EBTABLES_ATOMIC_FILE " environment variable."
+.TP
+.B -M, --modprobe "\fIprogram\fP"
+When talking to the kernel, use this
+.I program
+to try to automatically load missing kernel modules.
+.TP
+.B --concurrent
+Use a file lock to support concurrent scripts updating the ebtables kernel tables.
+
+.SS
+RULE SPECIFICATIONS
+The following command line arguments make up a rule specification (as used
+in the add and delete commands). A "!" option before the specification
+inverts the test for that specification. Apart from these standard rule
+specifications there are some other command line arguments of interest.
+See both the
+.BR "MATCH EXTENSIONS"
+and the
+.BR "WATCHER EXTENSIONS"
+below.
+.TP
+.BR "-p, --protocol " "[!] \fIprotocol\fP"
+The protocol that was responsible for creating the frame. This can be a
+hexadecimal number, above
+.IR 0x0600 ,
+a name (e.g.
+.I ARP
+) or
+.BR LENGTH .
+The protocol field of the Ethernet frame can be used to denote the
+length of the header (802.2/802.3 networks). When the value of that field is
+below or equals
+.IR 0x0600 ,
+the value equals the size of the header and shouldn't be used as a
+protocol number. Instead, all frames where the protocol field is used as
+the length field are assumed to be of the same 'protocol'. The protocol
+name used in ebtables for these frames is
+.BR LENGTH .
+.br
+The file
+.B /etc/ethertypes
+can be used to show readable
+characters instead of hexadecimal numbers for the protocols. For example,
+.I 0x0800
+will be represented by
+.IR IPV4 .
+The use of this file is not case sensitive.
+See that file for more information. The flag
+.B --proto
+is an alias for this option.
+.TP
+.BR "-i, --in-interface " "[!] \fIname\fP"
+The interface (bridge port) via which a frame is received (this option is useful in the
+.BR INPUT ,
+.BR FORWARD ,
+.BR PREROUTING " and " BROUTING
+chains). If the interface name ends with '+', then
+any interface name that begins with this name (disregarding '+') will match.
+The flag
+.B --in-if
+is an alias for this option.
+.TP
+.BR "--logical-in " "[!] \fIname\fP"
+The (logical) bridge interface via which a frame is received (this option is useful in the
+.BR INPUT ,
+.BR FORWARD ,
+.BR PREROUTING " and " BROUTING
+chains).
+If the interface name ends with '+', then
+any interface name that begins with this name (disregarding '+') will match.
+.TP
+.BR "-o, --out-interface " "[!] \fIname\fP"
+The interface (bridge port) via which a frame is going to be sent (this option is useful in the
+.BR OUTPUT ,
+.B FORWARD
+and
+.B POSTROUTING
+chains). If the interface name ends with '+', then
+any interface name that begins with this name (disregarding '+') will match.
+The flag
+.B --out-if
+is an alias for this option.
+.TP
+.BR "--logical-out " "[!] \fIname\fP"
+The (logical) bridge interface via which a frame is going to be sent (this option
+is useful in the
+.BR OUTPUT ,
+.B FORWARD
+and
+.B POSTROUTING
+chains).
+If the interface name ends with '+', then
+any interface name that begins with this name (disregarding '+') will match.
+.TP
+.BR "-s, --source " "[!] \fIaddress\fP[/\fImask\fP]"
+The source MAC address. Both mask and address are written as 6 hexadecimal
+numbers separated by colons. Alternatively one can specify Unicast,
+Multicast, Broadcast or BGA (Bridge Group Address):
+.br
+.IR "Unicast" "=00:00:00:00:00:00/01:00:00:00:00:00,"
+.IR "Multicast" "=01:00:00:00:00:00/01:00:00:00:00:00,"
+.IR "Broadcast" "=ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff or"
+.IR "BGA" "=01:80:c2:00:00:00/ff:ff:ff:ff:ff:ff."
+Note that a broadcast
+address will also match the multicast specification. The flag
+.B --src
+is an alias for this option.
+.TP
+.BR "-d, --destination " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination MAC address. See
+.B -s
+(above) for more details on MAC addresses. The flag
+.B --dst
+is an alias for this option.
+.TP
+.BR "-c, --set-counter " "\fIpcnt bcnt\fP"
+If used with
+.BR -A " or " -I ", then the packet and byte counters of the new rule will be set to
+.IR pcnt ", resp. " bcnt ".
+If used with the
+.BR -C " or " -D " commands, only rules with a packet and byte count equal to"
+.IR pcnt ", resp. " bcnt " will match."
+
+.SS MATCH EXTENSIONS
+Ebtables extensions are dynamically loaded into the userspace tool,
+there is therefore no need to explicitly load them with a
+-m option like is done in iptables.
+These extensions deal with functionality supported by kernel modules supplemental to
+the core ebtables code.
+.SS 802_3
+Specify 802.3 DSAP/SSAP fields or SNAP type. The protocol must be specified as
+.IR "LENGTH " "(see the option " " -p " above).
+.TP
+.BR "--802_3-sap " "[!] \fIsap\fP"
+DSAP and SSAP are two one byte 802.3 fields. The bytes are always
+equal, so only one byte (hexadecimal) is needed as an argument.
+.TP
+.BR "--802_3-type " "[!] \fItype\fP"
+If the 802.3 DSAP and SSAP values are 0xaa then the SNAP type field must
+be consulted to determine the payload protocol. This is a two byte
+(hexadecimal) argument. Only 802.3 frames with DSAP/SSAP 0xaa are
+checked for type.
+.\" .SS among
+.\" Match a MAC address or MAC/IP address pair versus a list of MAC addresses
+.\" and MAC/IP address pairs.
+.\" A list entry has the following format:
+.\" .IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple"
+.\" list entries are separated by a comma, specifying an IP address corresponding to
+.\" the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address
+.\" but different IP address (and vice versa) can be specified. If the MAC address doesn't
+.\" match any entry from the list, the frame doesn't match the rule (unless "!" was used).
+.\" .TP
+.\" .BR "--among-dst " "[!] \fIlist\fP"
+.\" Compare the MAC destination to the given list. If the Ethernet frame has type
+.\" .IR IPv4 " or " ARP ,
+.\" then comparison with MAC/IP destination address pairs from the
+.\" list is possible.
+.\" .TP
+.\" .BR "--among-src " "[!] \fIlist\fP"
+.\" Compare the MAC source to the given list. If the Ethernet frame has type
+.\" .IR IPv4 " or " ARP ,
+.\" then comparison with MAC/IP source address pairs from the list
+.\" is possible.
+.\" .TP
+.\" .BR "--among-dst-file " "[!] \fIfile\fP"
+.\" Same as
+.\" .BR --among-dst " but the list is read in from the specified file."
+.\" .TP
+.\" .BR "--among-src-file " "[!] \fIfile\fP"
+.\" Same as
+.\" .BR --among-src " but the list is read in from the specified file."
+.SS arp
+Specify (R)ARP fields. The protocol must be specified as
+.IR ARP " or " RARP .
+.TP
+.BR "--arp-opcode " "[!] \fIopcode\fP"
+The (R)ARP opcode (decimal or a string, for more details see
+.BR "ebtables -h arp" ).
+.TP
+.BR "--arp-htype " "[!] \fIhardware type\fP"
+The hardware type, this can be a decimal or the string
+.I Ethernet
+(which sets
+.I type
+to 1). Most (R)ARP packets have Eternet as hardware type.
+.TP
+.BR "--arp-ptype " "[!] \fIprotocol type\fP"
+The protocol type for which the (r)arp is used (hexadecimal or the string
+.IR IPv4 ,
+denoting 0x0800).
+Most (R)ARP packets have protocol type IPv4.
+.TP
+.BR "--arp-ip-src " "[!] \fIaddress\fP[/\fImask\fP]"
+The (R)ARP IP source address specification.
+.TP
+.BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+The (R)ARP IP destination address specification.
+.TP
+.BR "--arp-mac-src " "[!] \fIaddress\fP[/\fImask\fP]"
+The (R)ARP MAC source address specification.
+.TP
+.BR "--arp-mac-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+The (R)ARP MAC destination address specification.
+.TP
+.BR "" "[!]" " --arp-gratuitous"
+Checks for ARP gratuitous packets: checks equality of IPv4 source
+address and IPv4 destination address inside the ARP header.
+.SS ip
+Specify IPv4 fields. The protocol must be specified as
+.IR IPv4 .
+.TP
+.BR "--ip-source " "[!] \fIaddress\fP[/\fImask\fP]"
+The source IP address.
+The flag
+.B --ip-src
+is an alias for this option.
+.TP
+.BR "--ip-destination " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination IP address.
+The flag
+.B --ip-dst
+is an alias for this option.
+.TP
+.BR "--ip-tos " "[!] \fItos\fP"
+The IP type of service, in hexadecimal numbers.
+.BR IPv4 .
+.TP
+.BR "--ip-protocol " "[!] \fIprotocol\fP"
+The IP protocol.
+The flag
+.B --ip-proto
+is an alias for this option.
+.TP
+.BR "--ip-source-port " "[!] \fIport1\fP[:\fIport2\fP]"
+The source port or port range for the IP protocols 6 (TCP), 17
+(UDP), 33 (DCCP) or 132 (SCTP). The
+.B --ip-protocol
+option must be specified as
+.IR TCP ", " UDP ", " DCCP " or " SCTP .
+If
+.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used."
+The flag
+.B --ip-sport
+is an alias for this option.
+.TP
+.BR "--ip-destination-port " "[!] \fIport1\fP[:\fIport2\fP]"
+The destination port or port range for ip protocols 6 (TCP), 17
+(UDP), 33 (DCCP) or 132 (SCTP). The
+.B --ip-protocol
+option must be specified as
+.IR TCP ", " UDP ", " DCCP " or " SCTP .
+If
+.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used."
+The flag
+.B --ip-dport
+is an alias for this option.
+.SS ip6
+Specify IPv6 fields. The protocol must be specified as
+.IR IPv6 .
+.TP
+.BR "--ip6-source " "[!] \fIaddress\fP[/\fImask\fP]"
+The source IPv6 address.
+The flag
+.B --ip6-src
+is an alias for this option.
+.TP
+.BR "--ip6-destination " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination IPv6 address.
+The flag
+.B --ip6-dst
+is an alias for this option.
+.TP
+.BR "--ip6-tclass " "[!] \fItclass\fP"
+The IPv6 traffic class, in hexadecimal numbers.
+.TP
+.BR "--ip6-protocol " "[!] \fIprotocol\fP"
+The IP protocol.
+The flag
+.B --ip6-proto
+is an alias for this option.
+.TP
+.BR "--ip6-source-port " "[!] \fIport1\fP[:\fIport2\fP]"
+The source port or port range for the IPv6 protocols 6 (TCP), 17
+(UDP), 33 (DCCP) or 132 (SCTP). The
+.B --ip6-protocol
+option must be specified as
+.IR TCP ", " UDP ", " DCCP " or " SCTP .
+If
+.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used."
+The flag
+.B --ip6-sport
+is an alias for this option.
+.TP
+.BR "--ip6-destination-port " "[!] \fIport1\fP[:\fIport2\fP]"
+The destination port or port range for IPv6 protocols 6 (TCP), 17
+(UDP), 33 (DCCP) or 132 (SCTP). The
+.B --ip6-protocol
+option must be specified as
+.IR TCP ", " UDP ", " DCCP " or " SCTP .
+If
+.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used."
+The flag
+.B --ip6-dport
+is an alias for this option.
+.TP
+.BR "--ip6-icmp-type " "[!] {\fItype\fP[:\fItype\fP]/\fIcode\fP[:\fIcode\fP]|\fItypename\fP}"
+Specify ipv6\-icmp type and code to match.
+Ranges for both type and code are supported. Type and code are
+separated by a slash. Valid numbers for type and range are 0 to 255.
+To match a single type including all valid codes, symbolic names can
+be used instead of numbers. The list of known type names is shown by the command
+.nf
+ ebtables \-\-help ip6
+.fi
+This option is only valid for \-\-ip6-prococol ipv6-icmp.
+.SS limit
+This module matches at a limited rate using a token bucket filter.
+A rule using this extension will match until this limit is reached.
+It can be used with the
+.B --log
+watcher to give limited logging, for example. Its use is the same
+as the limit match of iptables.
+.TP
+.BR "--limit " "[\fIvalue\fP]"
+Maximum average matching rate: specified as a number, with an optional
+.IR /second ", " /minute ", " /hour ", or " /day " suffix; the default is " 3/hour .
+.TP
+.BR "--limit-burst " "[\fInumber\fP]"
+Maximum initial number of packets to match: this number gets recharged by
+one every time the limit specified above is not reached, up to this
+number; the default is
+.IR 5 .
+.SS mark_m
+.TP
+.BR "--mark " "[!] [\fIvalue\fP][/\fImask\fP]"
+Matches frames with the given unsigned mark value. If a
+.IR value " and " mask " are specified, the logical AND of the mark value of the frame and"
+the user-specified
+.IR mask " is taken before comparing it with the"
+user-specified mark
+.IR value ". When only a mark "
+.IR value " is specified, the packet"
+only matches when the mark value of the frame equals the user-specified
+mark
+.IR value .
+If only a
+.IR mask " is specified, the logical"
+AND of the mark value of the frame and the user-specified
+.IR mask " is taken and the frame matches when the result of this logical AND is"
+non-zero. Only specifying a
+.IR mask " is useful to match multiple mark values."
+.SS pkttype
+.TP
+.BR "--pkttype-type " "[!] \fItype\fP"
+Matches on the Ethernet "class" of the frame, which is determined by the
+generic networking code. Possible values:
+.IR broadcast " (MAC destination is the broadcast address),"
+.IR multicast " (MAC destination is a multicast address),"
+.IR host " (MAC destination is the receiving network device), or "
+.IR otherhost " (none of the above)."
+.SS stp
+Specify stp BPDU (bridge protocol data unit) fields. The destination
+address
+.BR "" ( -d ") must be specified as the bridge group address"
+.IR "" ( BGA ).
+For all options for which a range of values can be specified, it holds that
+if the lower bound is omitted (but the colon is not), then the lowest possible lower bound
+for that option is used, while if the upper bound is omitted (but the colon again is not), the
+highest possible upper bound for that option is used.
+.TP
+.BR "--stp-type " "[!] \fItype\fP"
+The BPDU type (0-255), recognized non-numerical types are
+.IR config ", denoting a configuration BPDU (=0), and"
+.IR tcn ", denothing a topology change notification BPDU (=128)."
+.TP
+.BR "--stp-flags " "[!] \fIflag\fP"
+The BPDU flag (0-255), recognized non-numerical flags are
+.IR topology-change ", denoting the topology change flag (=1), and"
+.IR topology-change-ack ", denoting the topology change acknowledgement flag (=128)."
+.TP
+.BR "--stp-root-prio " "[!] [\fIprio\fP][:\fIprio\fP]"
+The root priority (0-65535) range.
+.TP
+.BR "--stp-root-addr " "[!] [\fIaddress\fP][/\fImask\fP]"
+The root mac address, see the option
+.BR -s " for more details."
+.TP
+.BR "--stp-root-cost " "[!] [\fIcost\fP][:\fIcost\fP]"
+The root path cost (0-4294967295) range.
+.TP
+.BR "--stp-sender-prio " "[!] [\fIprio\fP][:\fIprio\fP]"
+The BPDU's sender priority (0-65535) range.
+.TP
+.BR "--stp-sender-addr " "[!] [\fIaddress\fP][/\fImask\fP]"
+The BPDU's sender mac address, see the option
+.BR -s " for more details."
+.TP
+.BR "--stp-port " "[!] [\fIport\fP][:\fIport\fP]"
+The port identifier (0-65535) range.
+.TP
+.BR "--stp-msg-age " "[!] [\fIage\fP][:\fIage\fP]"
+The message age timer (0-65535) range.
+.TP
+.BR "--stp-max-age " "[!] [\fIage\fP][:\fIage\fP]"
+The max age timer (0-65535) range.
+.TP
+.BR "--stp-hello-time " "[!] [\fItime\fP][:\fItime\fP]"
+The hello time timer (0-65535) range.
+.TP
+.BR "--stp-forward-delay " "[!] [\fIdelay\fP][:\fIdelay\fP]"
+The forward delay timer (0-65535) range.
+.\" .SS string
+.\" This module matches on a given string using some pattern matching strategy.
+.\" .TP
+.\" .BR "--string-algo " "\fIalgorithm\fP"
+.\" The pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
+.\" .TP
+.\" .BR "--string-from " "\fIoffset\fP"
+.\" The lowest offset from which a match can start. (default: 0)
+.\" .TP
+.\" .BR "--string-to " "\fIoffset\fP"
+.\" The highest offset from which a match can start. (default: size of frame)
+.\" .TP
+.\" .BR "--string " "[!] \fIpattern\fP"
+.\" Matches the given pattern.
+.\" .TP
+.\" .BR "--string-hex " "[!] \fIpattern\fP"
+.\" Matches the given pattern in hex notation, e.g. '|0D 0A|', '|0D0A|', 'www|09|netfilter|03|org|00|'
+.\" .TP
+.\" .BR "--string-icase"
+.\" Ignore case when searching.
+.SS vlan
+Specify 802.1Q Tag Control Information fields.
+The protocol must be specified as
+.IR 802_1Q " (0x8100)."
+.TP
+.BR "--vlan-id " "[!] \fIid\fP"
+The VLAN identifier field (VID). Decimal number from 0 to 4095.
+.TP
+.BR "--vlan-prio " "[!] \fIprio\fP"
+The user priority field, a decimal number from 0 to 7.
+The VID should be set to 0 ("null VID") or unspecified
+(in the latter case the VID is deliberately set to 0).
+.TP
+.BR "--vlan-encap " "[!] \fItype\fP"
+The encapsulated Ethernet frame type/length.
+Specified as a hexadecimal
+number from 0x0000 to 0xFFFF or as a symbolic name
+from
+.BR /etc/ethertypes .
+
+.SS WATCHER EXTENSIONS
+Watchers only look at frames passing by, they don't modify them nor decide
+to accept the frames or not. These watchers only
+see the frame if the frame matches the rule, and they see it before the
+target is executed.
+.SS log
+The log watcher writes descriptive data about a frame to the syslog.
+.TP
+.B "--log"
+.br
+Log with the default loggin options: log-level=
+.IR info ,
+log-prefix="", no ip logging, no arp logging.
+.TP
+.B --log-level "\fIlevel\fP"
+.br
+Defines the logging level. For the possible values, see
+.BR "ebtables -h log" .
+The default level is
+.IR info .
+.TP
+.BR --log-prefix " \fItext\fP"
+.br
+Defines the prefix
+.I text
+to be printed at the beginning of the line with the logging information.
+.TP
+.B --log-ip
+.br
+Will log the ip information when a frame made by the ip protocol matches
+the rule. The default is no ip information logging.
+.TP
+.B --log-ip6
+.br
+Will log the ipv6 information when a frame made by the ipv6 protocol matches
+the rule. The default is no ipv6 information logging.
+.TP
+.B --log-arp
+.br
+Will log the (r)arp information when a frame made by the (r)arp protocols
+matches the rule. The default is no (r)arp information logging.
+.SS nflog
+The nflog watcher passes the packet to the loaded logging backend
+in order to log the packet. This is usually used in combination with
+nfnetlink_log as logging backend, which will multicast the packet
+through a
+.IR netlink
+socket to the specified multicast group. One or more userspace processes
+may subscribe to the group to receive the packets.
+.TP
+.B "--nflog"
+.br
+Log with the default logging options
+.TP
+.B --nflog-group "\fInlgroup\fP"
+.br
+The netlink group (1 - 2^32-1) to which packets are (only applicable for
+nfnetlink_log). The default value is 1.
+.TP
+.B --nflog-prefix "\fIprefix\fP"
+.br
+A prefix string to include in the log message, up to 30 characters
+long, useful for distinguishing messages in the logs.
+.TP
+.B --nflog-range "\fIsize\fP"
+.br
+The number of bytes to be copied to userspace (only applicable for
+nfnetlink_log). nfnetlink_log instances may specify their own
+range, this option overrides it.
+.TP
+.B --nflog-threshold "\fIsize\fP"
+.br
+Number of packets to queue inside the kernel before sending them
+to userspace (only applicable for nfnetlink_log). Higher values
+result in less overhead per packet, but increase delay until the
+packets reach userspace. The default value is 1.
+.SS ulog
+The ulog watcher passes the packet to a userspace
+logging daemon using netlink multicast sockets. This differs
+from the log watcher in the sense that the complete packet is
+sent to userspace instead of a descriptive text and that
+netlink multicast sockets are used instead of the syslog.
+This watcher enables parsing of packets with userspace programs, the
+physical bridge in and out ports are also included in the netlink messages.
+The ulog watcher module accepts 2 parameters when the module is loaded
+into the kernel (e.g. with modprobe):
+.B nlbufsiz
+specifies how big the buffer for each netlink multicast
+group is. If you say
+.IR nlbufsiz=8192 ,
+for example, up to eight kB of packets will
+get accumulated in the kernel until they are sent to userspace. It is
+not possible to allocate more than 128kB. Please also keep in mind that
+this buffer size is allocated for each nlgroup you are using, so the
+total kernel memory usage increases by that factor. The default is 4096.
+.B flushtimeout
+specifies after how many hundredths of a second the queue should be
+flushed, even if it is not full yet. The default is 10 (one tenth of
+a second).
+.TP
+.B "--ulog"
+.br
+Use the default settings: ulog-prefix="", ulog-nlgroup=1,
+ulog-cprange=4096, ulog-qthreshold=1.
+.TP
+.B --ulog-prefix "\fItext\fP"
+.br
+Defines the prefix included with the packets sent to userspace.
+.TP
+.BR --ulog-nlgroup " \fIgroup\fP"
+.br
+Defines which netlink group number to use (a number from 1 to 32).
+Make sure the netlink group numbers used for the iptables ULOG
+target differ from those used for the ebtables ulog watcher.
+The default group number is 1.
+.TP
+.BR --ulog-cprange " \fIrange\fP"
+.br
+Defines the maximum copy range to userspace, for packets matching the
+rule. The default range is 0, which means the maximum copy range is
+given by
+.BR nlbufsiz .
+A maximum copy range larger than
+128*1024 is meaningless as the packets sent to userspace have an upper
+size limit of 128*1024.
+.TP
+.BR --ulog-qthreshold " \fIthreshold\fP"
+.br
+Queue at most
+.I threshold
+number of packets before sending them to
+userspace with a netlink socket. Note that packets can be sent to
+userspace before the queue is full, this happens when the ulog
+kernel timer goes off (the frequency of this timer depends on
+.BR flushtimeout ).
+.SS TARGET EXTENSIONS
+.SS arpreply
+The
+.B arpreply
+target can be used in the
+.BR PREROUTING " chain of the " nat " table."
+If this target sees an ARP request it will automatically reply
+with an ARP reply. The used MAC address for the reply can be specified.
+The protocol must be specified as
+.IR ARP .
+When the ARP message is not an ARP request or when the ARP request isn't
+for an IP address on an Ethernet network, it is ignored by this target
+.BR "" ( CONTINUE ).
+When the ARP request is malformed, it is dropped
+.BR "" ( DROP ).
+.TP
+.BR "--arpreply-mac " "\fIaddress\fP"
+Specifies the MAC address to reply with: the Ethernet source MAC and the
+ARP payload source MAC will be filled in with this address.
+.TP
+.BR "--arpreply-target " "\fItarget\fP"
+Specifies the standard target. After sending the ARP reply, the rule still
+has to give a standard target so ebtables knows what to do with the ARP request.
+The default target
+.BR "" "is " DROP .
+.SS dnat
+The
+.B dnat
+target can only be used in the
+.BR PREROUTING " and " OUTPUT " chains of the " nat " table."
+It specifies that the destination MAC address has to be changed.
+.TP
+.BR "--to-destination " "\fIaddress\fP"
+.br
+Change the destination MAC address to the specified
+.IR address .
+The flag
+.B --to-dst
+is an alias for this option.
+.TP
+.BR "--dnat-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the dnat, the rule still has to
+give a standard target so ebtables knows what to do with the dnated frame.
+The default target is
+.BR ACCEPT .
+Making it
+.BR CONTINUE " could let you use"
+multiple target extensions on the same frame. Making it
+.BR DROP " only makes"
+sense in the
+.BR BROUTING " chain but using the " redirect " target is more logical there. " RETURN " is also allowed. Note that using " RETURN
+in a base chain is not allowed (for obvious reasons).
+.SS mark
+.BR "" "The " mark " target can be used in every chain of every table. It is possible"
+to use the marking of a frame/packet in both ebtables and iptables,
+if the bridge-nf code is compiled into the kernel. Both put the marking at the
+same place. This allows for a form of communication between ebtables and iptables.
+.TP
+.BR "--mark-set " "\fIvalue\fP"
+.br
+Mark the frame with the specified non-negative
+.IR value .
+.TP
+.BR "--mark-or " "\fIvalue\fP"
+.br
+Or the frame with the specified non-negative
+.IR value .
+.TP
+.BR "--mark-and " "\fIvalue\fP"
+.br
+And the frame with the specified non-negative
+.IR value .
+.TP
+.BR "--mark-xor " "\fIvalue\fP"
+.br
+Xor the frame with the specified non-negative
+.IR value .
+.TP
+.BR "--mark-target " "\fItarget\fP"
+.br
+Specifies the standard target. After marking the frame, the rule
+still has to give a standard target so ebtables knows what to do.
+The default target is
+.BR ACCEPT ". Making it " CONTINUE " can let you do other"
+things with the frame in subsequent rules of the chain.
+.SS redirect
+The
+.B redirect
+target will change the MAC target address to that of the bridge device the
+frame arrived on. This target can only be used in the
+.BR PREROUTING " chain of the " nat " table."
+The MAC address of the bridge is used as destination address."
+.TP
+.BR "--redirect-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the MAC redirect, the rule
+still has to give a standard target so ebtables knows what to do.
+The default target is
+.BR ACCEPT ". Making it " CONTINUE " could let you use"
+multiple target extensions on the same frame. Making it
+.BR DROP " in the " BROUTING " chain will let the frames be routed. " RETURN " is also allowed. Note"
+.BR "" "that using " RETURN " in a base chain is not allowed."
+.SS snat
+The
+.B snat
+target can only be used in the
+.BR POSTROUTING " chain of the " nat " table."
+It specifies that the source MAC address has to be changed.
+.TP
+.BR "--to-source " "\fIaddress\fP"
+.br
+Changes the source MAC address to the specified
+.IR address ". The flag"
+.B --to-src
+is an alias for this option.
+.TP
+.BR "--snat-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the snat, the rule still has
+to give a standard target so ebtables knows what to do.
+.BR "" "The default target is " ACCEPT ". Making it " CONTINUE " could let you use"
+.BR "" "multiple target extensions on the same frame. Making it " DROP " doesn't"
+.BR "" "make sense, but you could do that too. " RETURN " is also allowed. Note"
+.BR "" "that using " RETURN " in a base chain is not allowed."
+.br
+.TP
+.BR "--snat-arp "
+.br
+Also change the hardware source address inside the arp header if the packet is an
+arp message and the hardware address length in the arp header is 6 bytes.
+.br
+.SH FILES
+.I /etc/ethertypes
+.SH ENVIRONMENT VARIABLES
+.I EBTABLES_ATOMIC_FILE
+.SH MAILINGLISTS
+.BR "" "See " http://netfilter.org/mailinglists.html
+.SH BUGS
+The version of ebtables this man page ships with does not support the
+.B broute
+table. Also there is no support for
+.BR among " and " string
+matches. And finally, this list is probably not complete.
+.SH SEE ALSO
+.BR xtables-nft "(8), " iptables "(8), " ip (8)
+.PP
+.BR "" "See " https://wiki.nftables.org
diff --git a/iptables/ip6tables-restore.c b/iptables/ip6tables-restore.c
deleted file mode 100644
index 3706b981..00000000
--- a/iptables/ip6tables-restore.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/* Code to restore the iptables state, from file by ip6tables-save.
- * Author: Andras Kis-Szabo <kisza@sch.bme.hu>
- *
- * based on iptables-restore
- * Authors:
- * Harald Welte <laforge@gnumonks.org>
- * Rusty Russell <rusty@linuxcare.com.au>
- * This code is distributed under the terms of GNU GPL v2
- */
-
-#include <getopt.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "ip6tables.h"
-#include "xshared.h"
-#include "xtables.h"
-#include "libiptc/libip6tc.h"
-#include "ip6tables-multi.h"
-
-static int counters, verbose, noflush, wait;
-
-static struct timeval wait_interval = {
- .tv_sec = 1,
-};
-
-/* Keeping track of external matches and targets. */
-static const struct option options[] = {
- {.name = "counters", .has_arg = 0, .val = 'c'},
- {.name = "verbose", .has_arg = 0, .val = 'v'},
- {.name = "version", .has_arg = 0, .val = 'V'},
- {.name = "test", .has_arg = 0, .val = 't'},
- {.name = "help", .has_arg = 0, .val = 'h'},
- {.name = "noflush", .has_arg = 0, .val = 'n'},
- {.name = "modprobe", .has_arg = 1, .val = 'M'},
- {.name = "table", .has_arg = 1, .val = 'T'},
- {.name = "wait", .has_arg = 2, .val = 'w'},
- {.name = "wait-interval", .has_arg = 2, .val = 'W'},
- {NULL},
-};
-
-#define prog_name ip6tables_globals.program_name
-#define prog_vers ip6tables_globals.program_version
-
-static void print_usage(const char *name, const char *version)
-{
- fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n"
- " [ --counters ]\n"
- " [ --verbose ]\n"
- " [ --version]\n"
- " [ --test ]\n"
- " [ --help ]\n"
- " [ --noflush ]\n"
- " [ --wait=<seconds>\n"
- " [ --wait-interval=<usecs>\n"
- " [ --table=<TABLE> ]\n"
- " [ --modprobe=<command> ]\n", name);
-}
-
-static struct xtc_handle *create_handle(const char *tablename)
-{
- struct xtc_handle *handle;
-
- handle = ip6tc_init(tablename);
-
- if (!handle) {
- /* try to insmod the module if iptc_init failed */
- xtables_load_ko(xtables_modprobe_program, false);
- handle = ip6tc_init(tablename);
- }
-
- if (!handle) {
- xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
- "table '%s'\n", prog_name, tablename);
- exit(1);
- }
- return handle;
-}
-
-int ip6tables_restore_main(int argc, char *argv[])
-{
- struct xtc_handle *handle = NULL;
- char buffer[10240];
- int c, lock;
- char curtable[XT_TABLE_MAXNAMELEN + 1] = {};
- FILE *in;
- int in_table = 0, testing = 0;
- const char *tablename = NULL;
- const struct xtc_ops *ops = &ip6tc_ops;
-
- line = 0;
- lock = XT_LOCK_NOT_ACQUIRED;
-
- ip6tables_globals.program_name = "ip6tables-restore";
- c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- ip6tables_globals.program_name,
- ip6tables_globals.program_version);
- exit(1);
- }
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions6();
-#endif
-
- while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) {
- switch (c) {
- case 'b':
- fprintf(stderr, "-b/--binary option is not implemented\n");
- break;
- case 'c':
- counters = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'V':
- printf("%s v%s (legacy)\n", prog_name, prog_vers);
- exit(0);
- case 't':
- testing = 1;
- break;
- case 'h':
- print_usage("ip6tables-restore",
- IPTABLES_VERSION);
- exit(0);
- case 'n':
- noflush = 1;
- break;
- case 'w':
- wait = parse_wait_time(argc, argv);
- break;
- case 'W':
- parse_wait_interval(argc, argv, &wait_interval);
- break;
- case 'M':
- xtables_modprobe_program = optarg;
- break;
- case 'T':
- tablename = optarg;
- break;
- default:
- fprintf(stderr,
- "Try `ip6tables-restore -h' for more information.\n");
- exit(1);
- }
- }
-
- if (optind == argc - 1) {
- in = fopen(argv[optind], "re");
- if (!in) {
- fprintf(stderr, "Can't open %s: %s\n", argv[optind],
- strerror(errno));
- exit(1);
- }
- }
- else if (optind < argc) {
- fprintf(stderr, "Unknown arguments found on commandline\n");
- exit(1);
- }
- else in = stdin;
-
- if (!wait_interval.tv_sec && !wait) {
- fprintf(stderr, "Option --wait-interval requires option --wait\n");
- exit(1);
- }
-
- /* Grab standard input. */
- while (fgets(buffer, sizeof(buffer), in)) {
- int ret = 0;
-
- line++;
- if (buffer[0] == '\n')
- continue;
- else if (buffer[0] == '#') {
- if (verbose)
- fputs(buffer, stdout);
- continue;
- } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
- if (!testing) {
- DEBUGP("Calling commit\n");
- ret = ops->commit(handle);
- ops->free(handle);
- handle = NULL;
- } else {
- DEBUGP("Not calling commit, testing\n");
- ret = 1;
- }
-
- /* Done with the current table, release the lock. */
- if (lock >= 0) {
- xtables_unlock(lock);
- lock = XT_LOCK_NOT_ACQUIRED;
- }
-
- in_table = 0;
- } else if ((buffer[0] == '*') && (!in_table)) {
- /* Acquire a lock before we create a new table handle */
- lock = xtables_lock_or_exit(wait, &wait_interval);
-
- /* New table */
- char *table;
-
- table = strtok(buffer+1, " \t\n");
- DEBUGP("line %u, table '%s'\n", line, table);
- if (!table) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name invalid\n",
- xt_params->program_name, line);
- exit(1);
- }
- strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
- curtable[XT_TABLE_MAXNAMELEN] = '\0';
-
- if (tablename != NULL && strcmp(tablename, table) != 0) {
- if (lock >= 0) {
- xtables_unlock(lock);
- lock = XT_LOCK_NOT_ACQUIRED;
- }
- continue;
- }
- if (handle)
- ops->free(handle);
-
- handle = create_handle(table);
- if (noflush == 0) {
- DEBUGP("Cleaning all chains of table '%s'\n",
- table);
- for_each_chain6(flush_entries6, verbose, 1,
- handle);
-
- DEBUGP("Deleting all user-defined chains "
- "of table '%s'\n", table);
- for_each_chain6(delete_chain6, verbose, 0,
- handle);
- }
-
- ret = 1;
- in_table = 1;
-
- } else if ((buffer[0] == ':') && (in_table)) {
- /* New chain. */
- char *policy, *chain;
-
- chain = strtok(buffer+1, " \t\n");
- DEBUGP("line %u, chain '%s'\n", line, chain);
- if (!chain) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- xt_params->program_name, line);
- exit(1);
- }
-
- if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s' "
- "(%u chars max)",
- chain, XT_EXTENSION_MAXNAMELEN - 1);
-
- if (ops->builtin(chain, handle) <= 0) {
- if (noflush && ops->is_chain(chain, handle)) {
- DEBUGP("Flushing existing user defined chain '%s'\n", chain);
- if (!ops->flush_entries(chain, handle))
- xtables_error(PARAMETER_PROBLEM,
- "error flushing chain "
- "'%s':%s\n", chain,
- strerror(errno));
- } else {
- DEBUGP("Creating new chain '%s'\n", chain);
- if (!ops->create_chain(chain, handle))
- xtables_error(PARAMETER_PROBLEM,
- "error creating chain "
- "'%s':%s\n", chain,
- strerror(errno));
- }
- }
-
- policy = strtok(NULL, " \t\n");
- DEBUGP("line %u, policy '%s'\n", line, policy);
- if (!policy) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u policy invalid\n",
- xt_params->program_name, line);
- exit(1);
- }
-
- if (strcmp(policy, "-") != 0) {
- struct xt_counters count = {};
-
- if (counters) {
- char *ctrs;
- ctrs = strtok(NULL, " \t\n");
-
- if (!ctrs || !parse_counters(ctrs, &count))
- xtables_error(PARAMETER_PROBLEM,
- "invalid policy counters "
- "for chain '%s'\n", chain);
- }
-
- DEBUGP("Setting policy of chain %s to %s\n",
- chain, policy);
-
- if (!ops->set_policy(chain, policy, &count,
- handle))
- xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s'"
- " on `%s' line %u: %s\n",
- policy, chain, line,
- ops->strerror(errno));
- }
-
- ret = 1;
-
- } else if (in_table) {
- int a;
- char *pcnt = NULL;
- char *bcnt = NULL;
- char *parsestart;
-
- if (buffer[0] == '[') {
- /* we have counters in our input */
- char *ptr = strchr(buffer, ']');
-
- if (!ptr)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- pcnt = strtok(buffer+1, ":");
- if (!pcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need :\n",
- line);
-
- bcnt = strtok(NULL, "]");
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- /* start command parsing after counter */
- parsestart = ptr + 1;
- } else {
- /* start command parsing at start of line */
- parsestart = buffer;
- }
-
- add_argv(argv[0], 0);
- add_argv("-t", 0);
- add_argv(curtable, 0);
-
- if (counters && pcnt && bcnt) {
- add_argv("--set-counters", 0);
- add_argv((char *) pcnt, 0);
- add_argv((char *) bcnt, 0);
- }
-
- add_param_to_argv(parsestart, line);
-
- DEBUGP("calling do_command6(%u, argv, &%s, handle):\n",
- newargc, curtable);
-
- for (a = 0; a < newargc; a++)
- DEBUGP("argv[%u]: %s\n", a, newargv[a]);
-
- ret = do_command6(newargc, newargv,
- &newargv[2], &handle, true);
-
- free_argv();
- fflush(stdout);
- }
- if (tablename != NULL && strcmp(tablename, curtable) != 0)
- continue;
- if (!ret) {
- fprintf(stderr, "%s: line %u failed\n",
- xt_params->program_name, line);
- exit(1);
- }
- }
- if (in_table) {
- fprintf(stderr, "%s: COMMIT expected at line %u\n",
- xt_params->program_name, line + 1);
- exit(1);
- }
-
- fclose(in);
- return 0;
-}
diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
deleted file mode 100644
index 5085982b..00000000
--- a/iptables/ip6tables-save.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* Code to save the ip6tables state, in human readable-form. */
-/* Author: Andras Kis-Szabo <kisza@sch.bme.hu>
- * Original code: iptables-save
- * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
- * Harald Welte <laforge@gnumonks.org>
- * This code is distributed under the terms of GNU GPL v2
- */
-#include <getopt.h>
-#include <errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include "libiptc/libip6tc.h"
-#include "ip6tables.h"
-#include "ip6tables-multi.h"
-
-#define prog_name ip6tables_globals.program_name
-#define prog_vers ip6tables_globals.program_version
-
-static int show_counters;
-
-static const struct option options[] = {
- {.name = "counters", .has_arg = false, .val = 'c'},
- {.name = "dump", .has_arg = false, .val = 'd'},
- {.name = "table", .has_arg = true, .val = 't'},
- {.name = "modprobe", .has_arg = true, .val = 'M'},
- {.name = "file", .has_arg = true, .val = 'f'},
- {.name = "version", .has_arg = false, .val = 'V'},
- {NULL},
-};
-
-
-/* Debugging prototype. */
-static int for_each_table(int (*func)(const char *tablename))
-{
- int ret = 1;
- FILE *procfile = NULL;
- char tablename[XT_TABLE_MAXNAMELEN+1];
- static const char filename[] = "/proc/net/ip6_tables_names";
-
- procfile = fopen(filename, "re");
- if (!procfile) {
- if (errno == ENOENT)
- return ret;
- fprintf(stderr, "Failed to list table names in %s: %s\n",
- filename, strerror(errno));
- exit(1);
- }
-
- while (fgets(tablename, sizeof(tablename), procfile)) {
- if (tablename[strlen(tablename) - 1] != '\n')
- xtables_error(OTHER_PROBLEM,
- "Badly formed tablename `%s'\n",
- tablename);
- tablename[strlen(tablename) - 1] = '\0';
- ret &= func(tablename);
- }
-
- fclose(procfile);
- return ret;
-}
-
-
-static int do_output(const char *tablename)
-{
- struct xtc_handle *h;
- const char *chain = NULL;
-
- if (!tablename)
- return for_each_table(&do_output);
-
- h = ip6tc_init(tablename);
- if (h == NULL) {
- xtables_load_ko(xtables_modprobe_program, false);
- h = ip6tc_init(tablename);
- }
- if (!h)
- xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
- ip6tc_strerror(errno));
-
- time_t now = time(NULL);
-
- printf("# Generated by ip6tables-save v%s on %s",
- IPTABLES_VERSION, ctime(&now));
- printf("*%s\n", tablename);
-
- /* Dump out chain names first,
- * thereby preventing dependency conflicts */
- for (chain = ip6tc_first_chain(h);
- chain;
- chain = ip6tc_next_chain(h)) {
-
- printf(":%s ", chain);
- if (ip6tc_builtin(chain, h)) {
- struct xt_counters count;
- printf("%s ",
- ip6tc_get_policy(chain, &count, h));
- printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
- } else {
- printf("- [0:0]\n");
- }
- }
-
- for (chain = ip6tc_first_chain(h);
- chain;
- chain = ip6tc_next_chain(h)) {
- const struct ip6t_entry *e;
-
- /* Dump out rules */
- e = ip6tc_first_rule(chain, h);
- while(e) {
- print_rule6(e, h, chain, show_counters);
- e = ip6tc_next_rule(e, h);
- }
- }
-
- now = time(NULL);
- printf("COMMIT\n");
- printf("# Completed on %s", ctime(&now));
- ip6tc_free(h);
-
- return 1;
-}
-
-/* Format:
- * :Chain name POLICY packets bytes
- * rule
- */
-int ip6tables_save_main(int argc, char *argv[])
-{
- const char *tablename = NULL;
- FILE *file = NULL;
- int ret, c;
-
- ip6tables_globals.program_name = "ip6tables-save";
- c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- ip6tables_globals.program_name,
- ip6tables_globals.program_version);
- exit(1);
- }
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions6();
-#endif
-
- while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) {
- switch (c) {
- case 'b':
- fprintf(stderr, "-b/--binary option is not implemented\n");
- break;
- case 'c':
- show_counters = 1;
- break;
-
- case 't':
- /* Select specific table. */
- tablename = optarg;
- break;
- case 'M':
- xtables_modprobe_program = optarg;
- break;
- case 'f':
- file = fopen(optarg, "w");
- if (file == NULL) {
- fprintf(stderr, "Failed to open file, error: %s\n",
- strerror(errno));
- exit(1);
- }
- ret = dup2(fileno(file), STDOUT_FILENO);
- if (ret == -1) {
- fprintf(stderr, "Failed to redirect stdout, error: %s\n",
- strerror(errno));
- exit(1);
- }
- fclose(file);
- break;
- case 'd':
- do_output(tablename);
- exit(0);
- case 'V':
- printf("%s v%s (legacy)\n", prog_name, prog_vers);
- exit(0);
- default:
- fprintf(stderr,
- "Look at manual page `ip6tables-save.8' for more information.\n");
- exit(1);
- }
- }
-
- if (optind < argc) {
- fprintf(stderr, "Unknown arguments found on commandline\n");
- exit(1);
- }
-
- return !do_output(tablename);
-}
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index fe089de4..050afa9a 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -1441,7 +1441,7 @@ int do_command6(int argc, char *argv[], char **table,
case 'j':
set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags,
cs.invert);
- command_jump(&cs);
+ command_jump(&cs, optarg);
break;
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index daee5fd9..575e619c 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -12,10 +12,13 @@
#include <stdio.h>
#include <stdlib.h>
#include "iptables.h"
+#include "ip6tables.h"
#include "xshared.h"
#include "xtables.h"
#include "libiptc/libiptc.h"
+#include "libiptc/libip6tc.h"
#include "iptables-multi.h"
+#include "ip6tables-multi.h"
static int counters, verbose, noflush, wait;
@@ -38,9 +41,6 @@ static const struct option options[] = {
{NULL},
};
-#define prog_name iptables_globals.program_name
-#define prog_vers iptables_globals.program_version
-
static void print_usage(const char *name, const char *version)
{
fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n"
@@ -56,28 +56,42 @@ static void print_usage(const char *name, const char *version)
" [ --modprobe=<command> ]\n", name);
}
-static struct xtc_handle *create_handle(const char *tablename)
+struct iptables_restore_cb {
+ const struct xtc_ops *ops;
+
+ int (*for_each_chain)(int (*fn)(const xt_chainlabel,
+ int, struct xtc_handle *),
+ int verbose, int builtinstoo,
+ struct xtc_handle *handle);
+ int (*flush_entries)(const xt_chainlabel, int, struct xtc_handle *);
+ int (*delete_chain)(const xt_chainlabel, int, struct xtc_handle *);
+ int (*do_command)(int argc, char *argv[], char **table,
+ struct xtc_handle **handle, bool restore);
+};
+
+static struct xtc_handle *
+create_handle(struct iptables_restore_cb *cb, const char *tablename)
{
struct xtc_handle *handle;
- handle = iptc_init(tablename);
+ handle = cb->ops->init(tablename);
if (!handle) {
/* try to insmod the module if iptc_init failed */
xtables_load_ko(xtables_modprobe_program, false);
- handle = iptc_init(tablename);
+ handle = cb->ops->init(tablename);
}
if (!handle) {
xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
- "table '%s'\n", prog_name, tablename);
+ "table '%s'\n", xt_params->program_name, tablename);
exit(1);
}
return handle;
}
-int
-iptables_restore_main(int argc, char *argv[])
+static int
+ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
{
struct xtc_handle *handle = NULL;
char buffer[10240];
@@ -86,24 +100,10 @@ iptables_restore_main(int argc, char *argv[])
FILE *in;
int in_table = 0, testing = 0;
const char *tablename = NULL;
- const struct xtc_ops *ops = &iptc_ops;
line = 0;
lock = XT_LOCK_NOT_ACQUIRED;
- iptables_globals.program_name = "iptables-restore";
- c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- iptables_globals.program_name,
- iptables_globals.program_version);
- exit(1);
- }
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
-#endif
-
while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) {
switch (c) {
case 'b':
@@ -116,13 +116,15 @@ iptables_restore_main(int argc, char *argv[])
verbose = 1;
break;
case 'V':
- printf("%s v%s (legacy)\n", prog_name, prog_vers);
+ printf("%s v%s (legacy)\n",
+ xt_params->program_name,
+ xt_params->program_version);
exit(0);
case 't':
testing = 1;
break;
case 'h':
- print_usage("iptables-restore",
+ print_usage(xt_params->program_name,
IPTABLES_VERSION);
exit(0);
case 'n':
@@ -142,7 +144,8 @@ iptables_restore_main(int argc, char *argv[])
break;
default:
fprintf(stderr,
- "Try `iptables-restore -h' for more information.\n");
+ "Try `%s -h' for more information.\n",
+ xt_params->program_name);
exit(1);
}
}
@@ -180,8 +183,8 @@ iptables_restore_main(int argc, char *argv[])
} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
if (!testing) {
DEBUGP("Calling commit\n");
- ret = ops->commit(handle);
- ops->free(handle);
+ ret = cb->ops->commit(handle);
+ cb->ops->free(handle);
handle = NULL;
} else {
DEBUGP("Not calling commit, testing\n");
@@ -213,7 +216,7 @@ iptables_restore_main(int argc, char *argv[])
strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
curtable[XT_TABLE_MAXNAMELEN] = '\0';
- if (tablename && (strcmp(tablename, table) != 0)) {
+ if (tablename && strcmp(tablename, table) != 0) {
if (lock >= 0) {
xtables_unlock(lock);
lock = XT_LOCK_NOT_ACQUIRED;
@@ -221,18 +224,18 @@ iptables_restore_main(int argc, char *argv[])
continue;
}
if (handle)
- ops->free(handle);
+ cb->ops->free(handle);
- handle = create_handle(table);
+ handle = create_handle(cb, table);
if (noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
- for_each_chain4(flush_entries4, verbose, 1,
+ cb->for_each_chain(cb->flush_entries, verbose, 1,
handle);
DEBUGP("Deleting all user-defined chains "
"of table '%s'\n", table);
- for_each_chain4(delete_chain4, verbose, 0,
+ cb->for_each_chain(cb->delete_chain, verbose, 0,
handle);
}
@@ -258,17 +261,17 @@ iptables_restore_main(int argc, char *argv[])
"(%u chars max)",
chain, XT_EXTENSION_MAXNAMELEN - 1);
- if (ops->builtin(chain, handle) <= 0) {
- if (noflush && ops->is_chain(chain, handle)) {
+ if (cb->ops->builtin(chain, handle) <= 0) {
+ if (noflush && cb->ops->is_chain(chain, handle)) {
DEBUGP("Flushing existing user defined chain '%s'\n", chain);
- if (!ops->flush_entries(chain, handle))
+ if (!cb->ops->flush_entries(chain, handle))
xtables_error(PARAMETER_PROBLEM,
"error flushing chain "
"'%s':%s\n", chain,
strerror(errno));
} else {
DEBUGP("Creating new chain '%s'\n", chain);
- if (!ops->create_chain(chain, handle))
+ if (!cb->ops->create_chain(chain, handle))
xtables_error(PARAMETER_PROBLEM,
"error creating chain "
"'%s':%s\n", chain,
@@ -294,20 +297,20 @@ iptables_restore_main(int argc, char *argv[])
if (!ctrs || !parse_counters(ctrs, &count))
xtables_error(PARAMETER_PROBLEM,
- "invalid policy counters "
- "for chain '%s'\n", chain);
+ "invalid policy counters "
+ "for chain '%s'\n", chain);
}
DEBUGP("Setting policy of chain %s to %s\n",
chain, policy);
- if (!ops->set_policy(chain, policy, &count,
+ if (!cb->ops->set_policy(chain, policy, &count,
handle))
xtables_error(OTHER_PROBLEM,
"Can't set policy `%s'"
" on `%s' line %u: %s\n",
policy, chain, line,
- ops->strerror(errno));
+ cb->ops->strerror(errno));
}
ret = 1;
@@ -358,19 +361,19 @@ iptables_restore_main(int argc, char *argv[])
add_param_to_argv(parsestart, line);
- DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
+ DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
newargc, curtable);
for (a = 0; a < newargc; a++)
DEBUGP("argv[%u]: %s\n", a, newargv[a]);
- ret = do_command4(newargc, newargv,
+ ret = cb->do_command(newargc, newargv,
&newargv[2], &handle, true);
free_argv();
fflush(stdout);
}
- if (tablename && (strcmp(tablename, curtable) != 0))
+ if (tablename && strcmp(tablename, curtable) != 0)
continue;
if (!ret) {
fprintf(stderr, "%s: line %u failed\n",
@@ -387,3 +390,66 @@ iptables_restore_main(int argc, char *argv[])
fclose(in);
return 0;
}
+
+
+#if defined ENABLE_IPV4
+struct iptables_restore_cb ipt_restore_cb = {
+ .ops = &iptc_ops,
+ .for_each_chain = for_each_chain4,
+ .flush_entries = flush_entries4,
+ .delete_chain = delete_chain4,
+ .do_command = do_command4,
+};
+
+int
+iptables_restore_main(int argc, char *argv[])
+{
+ int c;
+
+ iptables_globals.program_name = "iptables-restore";
+ c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
+ if (c < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ iptables_globals.program_name,
+ iptables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions4();
+#endif
+
+ return ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+}
+#endif
+
+#if defined ENABLE_IPV6
+struct iptables_restore_cb ip6t_restore_cb = {
+ .ops = &ip6tc_ops,
+ .for_each_chain = for_each_chain6,
+ .flush_entries = flush_entries6,
+ .delete_chain = delete_chain6,
+ .do_command = do_command6,
+};
+
+int
+ip6tables_restore_main(int argc, char *argv[])
+{
+ int c;
+
+ ip6tables_globals.program_name = "ip6tables-restore";
+ c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
+ if (c < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ ip6tables_globals.program_name,
+ ip6tables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions6();
+#endif
+
+ return ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+}
+#endif
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 51e11f3e..29ef2829 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -48,8 +48,11 @@ will log to STDOUT.
include the current values of all packet and byte counters in the output
.TP
\fB\-t\fR, \fB\-\-table\fR \fItablename\fP
-restrict output to only one table. If not specified, output includes all
-available tables.
+restrict output to only one table. If the kernel is configured with automatic
+module loading, an attempt will be made to load the appropriate module for
+that table if it is not already there.
+.br
+If not specified, output includes all available tables.
.SH BUGS
None known as of iptables-1.2.1 release
.SH AUTHORS
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index d694d212..826cb1e4 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -15,11 +15,12 @@
#include <netdb.h>
#include <unistd.h>
#include "libiptc/libiptc.h"
+#include "libiptc/libip6tc.h"
#include "iptables.h"
+#include "ip6tables.h"
#include "iptables-multi.h"
-
-#define prog_name iptables_globals.program_name
-#define prog_vers iptables_globals.program_version
+#include "ip6tables-multi.h"
+#include "xshared.h"
static int show_counters;
@@ -33,20 +34,26 @@ static const struct option options[] = {
{NULL},
};
-/* Debugging prototype. */
-static int for_each_table(int (*func)(const char *tablename))
+struct iptables_save_cb {
+ const struct xtc_ops *ops;
+
+ void (*dump_rules)(const char *chain, struct xtc_handle *handle);
+};
+
+static int
+for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename),
+ struct iptables_save_cb *cb)
{
int ret = 1;
FILE *procfile = NULL;
char tablename[XT_TABLE_MAXNAMELEN+1];
- static const char filename[] = "/proc/net/ip_tables_names";
- procfile = fopen(filename, "re");
+ procfile = fopen(afinfo->proc_exists, "re");
if (!procfile) {
if (errno == ENOENT)
return ret;
fprintf(stderr, "Failed to list table names in %s: %s\n",
- filename, strerror(errno));
+ afinfo->proc_exists, strerror(errno));
exit(1);
}
@@ -56,71 +63,65 @@ static int for_each_table(int (*func)(const char *tablename))
"Badly formed tablename `%s'\n",
tablename);
tablename[strlen(tablename) - 1] = '\0';
- ret &= func(tablename);
+ ret &= func(cb, tablename);
}
fclose(procfile);
return ret;
}
-
-static int do_output(const char *tablename)
+static int do_output(struct iptables_save_cb *cb, const char *tablename)
{
struct xtc_handle *h;
const char *chain = NULL;
if (!tablename)
- return for_each_table(&do_output);
+ return for_each_table(&do_output, cb);
- h = iptc_init(tablename);
+ h = cb->ops->init(tablename);
if (h == NULL) {
xtables_load_ko(xtables_modprobe_program, false);
- h = iptc_init(tablename);
+ h = cb->ops->init(tablename);
}
if (!h)
xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
- iptc_strerror(errno));
+ cb->ops->strerror(errno));
time_t now = time(NULL);
- printf("# Generated by iptables-save v%s on %s",
- IPTABLES_VERSION, ctime(&now));
+ printf("# Generated by %s v%s on %s",
+ xt_params->program_name, IPTABLES_VERSION, ctime(&now));
printf("*%s\n", tablename);
/* Dump out chain names first,
* thereby preventing dependency conflicts */
- for (chain = iptc_first_chain(h);
+ for (chain = cb->ops->first_chain(h);
chain;
- chain = iptc_next_chain(h)) {
+ chain = cb->ops->next_chain(h)) {
printf(":%s ", chain);
- if (iptc_builtin(chain, h)) {
+ if (cb->ops->builtin(chain, h)) {
struct xt_counters count;
- printf("%s ",
- iptc_get_policy(chain, &count, h));
- printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+
+ printf("%s ", cb->ops->get_policy(chain, &count, h));
+ printf("[%llu:%llu]\n",
+ (unsigned long long)count.pcnt,
+ (unsigned long long)count.bcnt);
} else {
printf("- [0:0]\n");
}
}
- for (chain = iptc_first_chain(h);
+ for (chain = cb->ops->first_chain(h);
chain;
- chain = iptc_next_chain(h)) {
- const struct ipt_entry *e;
-
- /* Dump out rules */
- e = iptc_first_rule(chain, h);
- while(e) {
- print_rule4(e, h, chain, show_counters);
- e = iptc_next_rule(e, h);
- }
+ chain = cb->ops->next_chain(h)) {
+ cb->dump_rules(chain, h);
}
now = time(NULL);
printf("COMMIT\n");
printf("# Completed on %s", ctime(&now));
- iptc_free(h);
+ cb->ops->free(h);
return 1;
}
@@ -129,26 +130,13 @@ static int do_output(const char *tablename)
* :Chain name POLICY packets bytes
* rule
*/
-int
-iptables_save_main(int argc, char *argv[])
+static int
+do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
{
const char *tablename = NULL;
FILE *file = NULL;
int ret, c;
- iptables_globals.program_name = "iptables-save";
- c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- iptables_globals.program_name,
- iptables_globals.program_version);
- exit(1);
- }
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
-#endif
-
while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) {
switch (c) {
case 'b':
@@ -181,14 +169,17 @@ iptables_save_main(int argc, char *argv[])
fclose(file);
break;
case 'd':
- do_output(tablename);
+ do_output(cb, tablename);
exit(0);
case 'V':
- printf("%s v%s (legacy)\n", prog_name, prog_vers);
+ printf("%s v%s (legacy)\n",
+ xt_params->program_name,
+ xt_params->program_version);
exit(0);
default:
fprintf(stderr,
- "Look at manual page `iptables-save.8' for more information.\n");
+ "Look at manual page `%s.8' for more information.\n",
+ xt_params->program_name);
exit(1);
}
}
@@ -198,5 +189,87 @@ iptables_save_main(int argc, char *argv[])
exit(1);
}
- return !do_output(tablename);
+ return !do_output(cb, tablename);
+}
+
+#ifdef ENABLE_IPV4
+static void iptables_dump_rules(const char *chain, struct xtc_handle *h)
+{
+ const struct ipt_entry *e;
+
+ /* Dump out rules */
+ e = iptc_first_rule(chain, h);
+ while(e) {
+ print_rule4(e, h, chain, show_counters);
+ e = iptc_next_rule(e, h);
+ }
+}
+
+struct iptables_save_cb ipt_save_cb = {
+ .ops = &iptc_ops,
+ .dump_rules = iptables_dump_rules,
+};
+
+/* Format:
+ * :Chain name POLICY packets bytes
+ * rule
+ */
+int
+iptables_save_main(int argc, char *argv[])
+{
+ iptables_globals.program_name = "iptables-save";
+ if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ iptables_globals.program_name,
+ iptables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions4();
+#endif
+
+ return do_iptables_save(&ipt_save_cb, argc, argv);
+}
+#endif /* ENABLE_IPV4 */
+
+#ifdef ENABLE_IPV6
+static void ip6tables_dump_rules(const char *chain, struct xtc_handle *h)
+{
+ const struct ip6t_entry *e;
+
+ /* Dump out rules */
+ e = ip6tc_first_rule(chain, h);
+ while(e) {
+ print_rule6(e, h, chain, show_counters);
+ e = ip6tc_next_rule(e, h);
+ }
+}
+
+struct iptables_save_cb ip6t_save_cb = {
+ .ops = &ip6tc_ops,
+ .dump_rules = ip6tables_dump_rules,
+};
+
+/* Format:
+ * :Chain name POLICY packets bytes
+ * rule
+ */
+int
+ip6tables_save_main(int argc, char *argv[])
+{
+ ip6tables_globals.program_name = "ip6tables-save";
+ if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ ip6tables_globals.program_name,
+ ip6tables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions6();
+#endif
+
+ return do_iptables_save(&ip6t_save_cb, argc, argv);
}
+#endif /* ENABLE_IPV6 */
diff --git a/iptables/iptables.c b/iptables/iptables.c
index f8041f56..38c4bfe8 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -1421,7 +1421,7 @@ int do_command4(int argc, char *argv[], char **table,
case 'j':
set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
cs.invert);
- command_jump(&cs);
+ command_jump(&cs, optarg);
break;
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 1a98996f..9805bbe0 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -29,7 +29,7 @@
#include "nft.h"
/* a few names */
-char *opcodes[] =
+char *arp_opcodes[] =
{
"Request",
"Reply",
@@ -338,7 +338,8 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
struct in_addr addr;
- unsigned short int ar_hrd, ar_pro, ar_op, ar_hln;
+ uint16_t ar_hrd, ar_pro, ar_op;
+ uint8_t ar_hln;
bool inv;
switch (ctx->payload.offset) {
@@ -364,7 +365,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
fw->arp.invflags |= ARPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
- get_cmp_data(e, &ar_hln, sizeof(ar_op), &inv);
+ get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
@@ -412,56 +413,6 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_arp_rule_to_cs(const struct nftnl_rule *r,
- struct iptables_command_state *cs)
-{
- struct nftnl_expr_iter *iter;
- struct nftnl_expr *expr;
- int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
- struct nft_xt_ctx ctx = {
- .cs = cs,
- .family = family,
- };
-
- iter = nftnl_expr_iter_create(r);
- if (iter == NULL)
- return;
-
- ctx.iter = iter;
- expr = nftnl_expr_iter_next(iter);
- while (expr != NULL) {
- const char *name =
- nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
-
- if (strcmp(name, "counter") == 0)
- nft_parse_counter(expr, &ctx.cs->arp.counters);
- else if (strcmp(name, "payload") == 0)
- nft_parse_payload(&ctx, expr);
- else if (strcmp(name, "meta") == 0)
- nft_parse_meta(&ctx, expr);
- else if (strcmp(name, "bitwise") == 0)
- nft_parse_bitwise(&ctx, expr);
- else if (strcmp(name, "cmp") == 0)
- nft_parse_cmp(&ctx, expr);
- else if (strcmp(name, "immediate") == 0)
- nft_parse_immediate(&ctx, expr);
- else if (strcmp(name, "target") == 0)
- nft_parse_target(&ctx, expr);
-
- expr = nftnl_expr_iter_next(iter);
- }
-
- nftnl_expr_iter_destroy(iter);
-
- if (cs->jumpto != NULL)
- return;
-
- if (cs->target != NULL && cs->target->name != NULL)
- cs->target = xtables_find_target(cs->target->name, XTF_TRY_LOAD);
- else
- cs->jumpto = "";
-}
-
static void nft_arp_print_header(unsigned int format, const char *chain,
const char *pol,
const struct xt_counters *counters,
@@ -484,14 +435,21 @@ static void nft_arp_print_header(unsigned int format, const char *chain,
}
}
-static void nft_arp_print_rule_details(const struct arpt_entry *fw,
+static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
unsigned int format)
{
+ const struct arpt_entry *fw = &cs->arp;
char buf[BUFSIZ];
char iface[IFNAMSIZ+2];
+ const char *sep = "";
int print_iface = 0;
int i;
+ if (strlen(cs->jumpto)) {
+ printf("%s-j %s", sep, cs->jumpto);
+ sep = " ";
+ }
+
iface[0] = '\0';
if (fw->arp.iniface[0] != '\0') {
@@ -503,9 +461,11 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw,
if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
}
- if (print_iface)
- printf("%s-i %s ", fw->arp.invflags & ARPT_INV_VIA_IN ?
+ if (print_iface) {
+ printf("%s%s-i %s", sep, fw->arp.invflags & ARPT_INV_VIA_IN ?
"! " : "", iface);
+ sep = " ";
+ }
print_iface = 0;
iface[0] = '\0';
@@ -519,12 +479,14 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw,
if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
}
- if (print_iface)
- printf("%s-o %s ", fw->arp.invflags & ARPT_INV_VIA_OUT ?
+ if (print_iface) {
+ printf("%s%s-o %s", sep, fw->arp.invflags & ARPT_INV_VIA_OUT ?
"! " : "", iface);
+ sep = " ";
+ }
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s", fw->arp.invflags & ARPT_INV_SRCIP
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
@@ -532,7 +494,8 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw,
sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
sizeof(buf) - strlen(buf) - 1);
- printf("-s %s ", buf);
+ printf("-s %s", buf);
+ sep = " ";
}
for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
@@ -540,16 +503,16 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw,
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devsrc;
- printf("%s", fw->arp.invflags & ARPT_INV_SRCDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR
? "! " : "");
printf("--src-mac ");
print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
(unsigned char *)fw->arp.src_devaddr.mask, ETH_ALEN);
- printf(" ");
+ sep = " ";
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s", fw->arp.invflags & ARPT_INV_TGTIP
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
@@ -557,7 +520,8 @@ after_devsrc:
sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
sizeof(buf) - strlen(buf) - 1);
- printf("-d %s ", buf);
+ printf("-d %s", buf);
+ sep = " ";
}
for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
@@ -565,43 +529,43 @@ after_devsrc:
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devdst;
- printf("%s", fw->arp.invflags & ARPT_INV_TGTDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR
? "! " : "");
printf("--dst-mac ");
print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
(unsigned char *)fw->arp.tgt_devaddr.mask, ETH_ALEN);
- printf(" ");
+ sep = " ";
after_devdst:
- if (fw->arp.arhln_mask != 0) {
- printf("%s", fw->arp.invflags & ARPT_INV_ARPHLN
+ if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN
? "! " : "");
printf("--h-length %d", fw->arp.arhln);
if (fw->arp.arhln_mask != 255)
printf("/%d", fw->arp.arhln_mask);
- printf(" ");
+ sep = " ";
}
if (fw->arp.arpop_mask != 0) {
int tmp = ntohs(fw->arp.arpop);
- printf("%s", fw->arp.invflags & ARPT_INV_ARPOP
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPOP
? "! " : "");
if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
- printf("--opcode %s", opcodes[tmp-1]);
+ printf("--opcode %s", arp_opcodes[tmp-1]);
else
printf("--opcode %d", tmp);
if (fw->arp.arpop_mask != 65535)
printf("/%d", ntohs(fw->arp.arpop_mask));
- printf(" ");
+ sep = " ";
}
- if (fw->arp.arhrd_mask != 0) {
+ if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
uint16_t tmp = ntohs(fw->arp.arhrd);
- printf("%s", fw->arp.invflags & ARPT_INV_ARPHRD
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHRD
? "! " : "");
if (tmp == 1 && !(format & FMT_NUMERIC))
printf("--h-type %s", "Ethernet");
@@ -609,13 +573,13 @@ after_devdst:
printf("--h-type %u", tmp);
if (fw->arp.arhrd_mask != 65535)
printf("/%d", ntohs(fw->arp.arhrd_mask));
- printf(" ");
+ sep = " ";
}
if (fw->arp.arpro_mask != 0) {
int tmp = ntohs(fw->arp.arpro);
- printf("%s", fw->arp.invflags & ARPT_INV_ARPPRO
+ printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPPRO
? "! " : "");
if (tmp == 0x0800 && !(format & FMT_NUMERIC))
printf("--proto-type %s", "IPv4");
@@ -623,18 +587,10 @@ after_devdst:
printf("--proto-type 0x%x", tmp);
if (fw->arp.arpro_mask != 65535)
printf("/%x", ntohs(fw->arp.arpro_mask));
- printf(" ");
+ sep = " ";
}
}
-static void nft_arp_save_counters(const void *data)
-{
- const struct iptables_command_state *cs = data;
-
- printf("[%llu:%llu] ", (unsigned long long)cs->arp.counters.pcnt,
- (unsigned long long)cs->arp.counters.bcnt);
-}
-
static void
nft_arp_save_rule(const void *data, unsigned int format)
{
@@ -642,18 +598,10 @@ nft_arp_save_rule(const void *data, unsigned int format)
format |= FMT_NUMERIC;
- nft_arp_print_rule_details(&cs->arp, format);
-
- if (cs->jumpto != NULL && strcmp(cs->jumpto, "") != 0) {
- printf("-j %s", cs->jumpto);
- } else if (cs->target) {
- printf("-j %s", cs->target->name);
- if (cs->target->save != NULL)
- cs->target->save(&cs->arp, cs->target->t);
- }
-
- if (!(format & FMT_NONEWLINE))
- fputc('\n', stdout);
+ nft_arp_print_rule_details(cs, format);
+ if (cs->target && cs->target->save)
+ cs->target->save(&cs->fw, cs->target->t);
+ printf("\n");
}
static void
@@ -664,22 +612,16 @@ nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format)
if (format & FMT_LINENUMBERS)
printf("%u ", num);
- nft_arp_rule_to_cs(r, &cs);
-
- nft_arp_print_rule_details(&cs.arp, format);
+ nft_rule_to_iptables_command_state(r, &cs);
- if (cs.jumpto != NULL && strcmp(cs.jumpto, "") != 0) {
- printf("-j %s", cs.jumpto);
- } else if (cs.target) {
- printf("-j %s", cs.target->name);
- cs.target->print(&cs.arp, cs.target->t, format & FMT_NUMERIC);
- }
+ nft_arp_print_rule_details(&cs, format);
+ print_matches_and_target(&cs, format);
if (!(format & FMT_NOCOUNTS)) {
- printf(", pcnt=");
- xtables_print_num(cs.arp.counters.pcnt, format);
+ printf(" , pcnt=");
+ xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE);
printf("-- bcnt=");
- xtables_print_num(cs.arp.counters.bcnt, format);
+ xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE);
}
if (!(format & FMT_NONEWLINE))
@@ -718,20 +660,24 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
{
const struct iptables_command_state *cs = data;
struct iptables_command_state this = {};
+ bool ret = false;
/* Delete by matching rule case */
- nft_arp_rule_to_cs(r, &this);
+ nft_rule_to_iptables_command_state(r, &this);
if (!nft_arp_is_same(&cs->arp, &this.arp))
- return false;
+ goto out;
if (!compare_targets(cs->target, this.target))
- return false;
+ goto out;
if (this.jumpto && strcmp(cs->jumpto, this.jumpto) != 0)
- return false;
+ goto out;
- return true;
+ ret = true;
+out:
+ ops->clear_cs(&this);
+ return ret;
}
static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
@@ -751,10 +697,10 @@ 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 = nft_arp_save_counters,
+ .save_counters = save_counters,
.save_chain = nft_arp_save_chain,
.post_parse = NULL,
- .rule_to_cs = nft_arp_rule_to_cs,
+ .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-arp.h b/iptables/nft-arp.h
index da6bd380..3411fc3d 100644
--- a/iptables/nft-arp.h
+++ b/iptables/nft-arp.h
@@ -1,7 +1,7 @@
#ifndef _NFT_ARP_H_
#define _NFT_ARP_H_
-extern char *opcodes[];
+extern char *arp_opcodes[];
#define NUMOPCODES 9
#endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index ad583a60..ddfbee16 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -45,6 +45,16 @@ void ebt_cs_clean(struct iptables_command_state *cs)
free(m);
m = nm;
}
+
+ if (cs->target) {
+ free(cs->target->t);
+ cs->target->t = NULL;
+
+ if (cs->target == cs->target->next) {
+ free(cs->target);
+ cs->target = NULL;
+ }
+ }
}
static void ebt_print_mac(const unsigned char *mac)
@@ -334,7 +344,7 @@ static void nft_rule_to_ebtables_command_state(const struct nftnl_rule *r,
static void print_iface(const char *option, const char *name, bool invert)
{
if (*name)
- printf("%s%s %s ", invert ? "! " : "", option, name);
+ printf("%s%s %s ", option, invert ? " !" : "", name);
}
static void nft_bridge_print_table_header(const char *tablename)
@@ -348,7 +358,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain,
bool basechain, uint32_t refs, uint32_t entries)
{
printf("Bridge chain: %s, entries: %u, policy: %s\n",
- chain, entries, basechain ? pol : "RETURN");
+ chain, entries, pol ?: "RETURN");
}
static void print_matches_and_watchers(const struct iptables_command_state *cs,
@@ -379,9 +389,9 @@ static void print_mac(char option, const unsigned char *mac,
const unsigned char *mask,
bool invert)
{
+ printf("-%c ", option);
if (invert)
printf("! ");
- printf("-%c ", option);
ebt_print_mac_and_mask(mac, mask);
printf(" ");
}
@@ -396,9 +406,9 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
if (bitmask & EBT_NOPROTO)
return;
+ printf("-p ");
if (invert)
printf("! ");
- printf("-p ");
if (bitmask & EBT_802_3) {
printf("length ");
@@ -469,6 +479,11 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
(uint64_t)cs->counters.pcnt,
(uint64_t)cs->counters.bcnt);
+ if (!(format & FMT_NOCOUNTS))
+ printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
+ (uint64_t)cs->counters.pcnt,
+ (uint64_t)cs->counters.bcnt);
+
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
}
@@ -482,11 +497,7 @@ static void nft_bridge_print_rule(struct nftnl_rule *r, unsigned int num,
printf("%d ", num);
nft_rule_to_ebtables_command_state(r, &cs);
- nft_bridge_save_rule(&cs, format & ~FMT_EBT_SAVE);
- if (!(format & FMT_NOCOUNTS))
- printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
- (uint64_t)cs.counters.pcnt,
- (uint64_t)cs.counters.bcnt);
+ nft_bridge_save_rule(&cs, format);
ebt_cs_clean(&cs);
}
@@ -547,30 +558,34 @@ static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule *
{
struct iptables_command_state *cs = data;
struct iptables_command_state this = {};
+ bool ret = false;
nft_rule_to_ebtables_command_state(r, &this);
DEBUGP("comparing with... ");
if (!nft_bridge_is_same(cs, &this))
- return false;
+ goto out;
if (!compare_matches(cs->matches, this.matches)) {
DEBUGP("Different matches\n");
- return false;
+ goto out;
}
if (!compare_targets(cs->target, this.target)) {
DEBUGP("Different target\n");
- return false;
+ goto out;
}
if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) {
DEBUGP("Different verdict\n");
- return false;
+ goto out;
}
- return true;
+ ret = true;
+out:
+ ops->clear_cs(&this);
+ return ret;
}
static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h
index de52cd71..d90066f1 100644
--- a/iptables/nft-bridge.h
+++ b/iptables/nft-bridge.h
@@ -32,7 +32,6 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas
*/
#define EBT_TABLE_MAXNAMELEN 32
-#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
/* verdicts >0 are "branches" */
@@ -122,6 +121,5 @@ void ebt_add_match(struct xtables_match *m,
void ebt_add_watcher(struct xtables_target *watcher,
struct iptables_command_state *cs);
int ebt_command_default(struct iptables_command_state *cs);
-struct xtables_target *ebt_command_jump(const char *jumpto);
#endif
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index ffb439b4..4497eb9b 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -77,17 +77,9 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- /* Use nft built-in comments support instead of comment match */
- if (strcmp(matchp->match->name, "comment") == 0) {
- ret = add_comment(r, (char *)matchp->match->m->data);
- if (ret < 0)
- goto try_match;
- } else {
-try_match:
- ret = add_match(r, matchp->match->m);
- if (ret < 0)
- return ret;
- }
+ ret = add_match(r, matchp->match->m);
+ if (ret < 0)
+ return ret;
}
/* Counters need to me added before the target, otherwise they are
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 7bacee4a..cacb1c9e 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -66,17 +66,9 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- /* Use nft built-in comments support instead of comment match */
- if (strcmp(matchp->match->name, "comment") == 0) {
- ret = add_comment(r, (char *)matchp->match->m->data);
- if (ret < 0)
- goto try_match;
- } else {
-try_match:
- ret = add_match(r, matchp->match->m);
- if (ret < 0)
- return ret;
- }
+ ret = add_match(r, matchp->match->m);
+ if (ret < 0)
+ return ret;
}
/* Counters need to me added before the target, otherwise they are
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 7b8ca5e4..1c09277d 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -302,7 +302,7 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
return 0;
}
-void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
uint32_t tg_len;
const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME);
@@ -331,7 +331,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ops->parse_target(target, data);
}
-void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
uint32_t mt_len;
const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME);
@@ -433,7 +433,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
ops->parse_target(target, ctx->cs);
}
-void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
@@ -449,14 +449,14 @@ void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->flags |= NFT_XT_CTX_META;
}
-void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
ctx->flags |= NFT_XT_CTX_PAYLOAD;
}
-void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
uint32_t reg, len;
const void *data;
@@ -472,7 +472,7 @@ void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->flags |= NFT_XT_CTX_BITWISE;
}
-void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
void *data = ctx->cs;
@@ -493,13 +493,13 @@ void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
}
}
-void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
+static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
{
counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS);
counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES);
}
-void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
struct nft_family_ops *ops;
@@ -639,40 +639,65 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) {
const void *data;
uint32_t len, size;
- struct xtables_match *match;
- struct xt_entry_match *m;
+ const char *comment;
data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
- match = xtables_find_match("comment", XTF_TRY_LOAD,
- &cs->matches);
- if (match == NULL)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
- m = xtables_calloc(1, size);
-
- strncpy((char *)m->data, get_comment(data, len),
- match->size - 1);
- m->u.match_size = size;
- m->u.user.revision = 0;
- strcpy(m->u.user.name, match->name);
-
- match->m = m;
+ comment = get_comment(data, len);
+ if (comment) {
+ struct xtables_match *match;
+ struct xt_entry_match *m;
+
+ match = xtables_find_match("comment", XTF_TRY_LOAD,
+ &cs->matches);
+ if (match == NULL)
+ return;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_match))
+ + match->size;
+ m = xtables_calloc(1, size);
+
+ strncpy((char *)m->data, comment, match->size - 1);
+ m->u.match_size = size;
+ m->u.user.revision = 0;
+ strcpy(m->u.user.name, match->name);
+
+ match->m = m;
+ }
}
- if (cs->target != NULL)
+ if (cs->target != NULL) {
cs->jumpto = cs->target->name;
- else if (cs->jumpto != NULL)
+ } else if (cs->jumpto != NULL) {
+ struct xt_entry_target *t;
+ uint32_t size;
+
cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
- else
+ if (!cs->target)
+ return;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
+ t = xtables_calloc(1, size);
+ t->u.target_size = size;
+ t->u.user.revision = cs->target->revision;
+ strcpy(t->u.user.name, cs->jumpto);
+ cs->target->t = t;
+ } else {
cs->jumpto = "";
+ }
}
void nft_clear_iptables_command_state(struct iptables_command_state *cs)
{
xtables_rule_matches_free(&cs->matches);
- if (cs->target)
+ if (cs->target) {
free(cs->target->t);
+ cs->target->t = NULL;
+
+ if (cs->target == cs->target->next) {
+ free(cs->target);
+ cs->target = NULL;
+ }
+ }
}
void print_header(unsigned int format, const char *chain, const char *pol,
@@ -961,6 +986,7 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops,
struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data, this = {};
+ bool ret = false;
nft_rule_to_iptables_command_state(r, &this);
@@ -969,24 +995,27 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops,
nft_rule_print_save(r, NFT_RULE_APPEND, 0);
#endif
if (!ops->is_same(cs, &this))
- return false;
+ goto out;
if (!compare_matches(cs->matches, this.matches)) {
DEBUGP("Different matches\n");
- return false;
+ goto out;
}
if (!compare_targets(cs->target, this.target)) {
DEBUGP("Different target\n");
- return false;
+ goto out;
}
if (strcmp(cs->jumpto, this.jumpto) != 0) {
DEBUGP("Different verdict\n");
- return false;
+ goto out;
}
- return true;
+ ret = true;
+out:
+ ops->clear_cs(&this);
+ return ret;
}
void nft_check_xt_legacy(int family, bool is_ipt_save)
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index e3ecdb4d..de889ead 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -137,14 +137,6 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *outiface_mask, uint8_t *invflags);
void print_proto(uint16_t proto, int invert);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
-void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
-void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters);
-void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
struct iptables_command_state *cs);
void nft_clear_iptables_command_state(struct iptables_command_state *cs);
@@ -251,17 +243,13 @@ struct nftnl_chain_list;
struct nft_xt_restore_cb {
void (*table_new)(struct nft_handle *h, const char *table);
- struct nftnl_chain_list *(*chain_list)(struct nft_handle *h);
- void (*chain_del)(struct nftnl_chain_list *clist, const char *curtable,
- const char *chain);
- int (*chain_user_flush)(struct nft_handle *h,
- struct nftnl_chain_list *clist,
- const char *table, const char *chain);
+ struct nftnl_chain_list *(*chain_list)(struct nft_handle *h,
+ const char *table);
int (*chain_set)(struct nft_handle *h, const char *table,
const char *chain, const char *policy,
const struct xt_counters *counters);
- int (*chain_user_add)(struct nft_handle *h, const char *chain,
- const char *table);
+ int (*chain_restore)(struct nft_handle *h, const char *chain,
+ const char *table);
int (*table_flush)(struct nft_handle *h, const char *table);
diff --git a/iptables/nft.c b/iptables/nft.c
index e8538d38..2c615214 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -41,6 +41,7 @@
#include <linux/netfilter/xt_limit.h>
#include <libmnl/libmnl.h>
+#include <libnftnl/gen.h>
#include <libnftnl/table.h>
#include <libnftnl/chain.h>
#include <libnftnl/rule.h>
@@ -55,10 +56,41 @@
#include "nft.h"
#include "xshared.h" /* proto_to_name */
#include "nft-shared.h"
+#include "nft-bridge.h" /* EBT_NOPROTO */
#include "xtables-config-parser.h"
static void *nft_fn;
+static int genid_cb(const struct nlmsghdr *nlh, void *data)
+{
+ uint32_t *genid = data;
+ struct nftnl_gen *gen;
+
+ gen = nftnl_gen_alloc();
+ if (!gen)
+ return MNL_CB_ERROR;
+
+ if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
+ goto out;
+
+ *genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
+
+ nftnl_gen_free(gen);
+ return MNL_CB_STOP;
+out:
+ nftnl_gen_free(gen);
+ return MNL_CB_ERROR;
+}
+
+static int mnl_genid_get(struct nft_handle *h, uint32_t *genid)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
+ return mnl_talk(h, nlh, genid_cb, genid);
+}
+
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data)
@@ -108,9 +140,14 @@ static void mnl_nft_batch_continue(struct nftnl_batch *batch)
assert(nftnl_batch_update(batch) >= 0);
}
-static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum)
+static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum)
{
- nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
+
+ mnl_attr_put_u32(nlh, NFTA_GEN_ID, htonl(genid));
+
mnl_nft_batch_continue(batch);
return seqnum;
@@ -263,7 +300,9 @@ enum obj_action {
struct obj_update {
struct list_head head;
- enum obj_update_type type;
+ enum obj_update_type type:8;
+ uint8_t skip:1;
+ uint8_t implicit:1;
unsigned int seq;
union {
struct nftnl_table *table;
@@ -341,13 +380,13 @@ static int mnl_append_error(const struct nft_handle *h,
return snprintf(buf, len, "%s: %s", errmsg, tcr);
}
-static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
+static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
{
struct obj_update *obj;
obj = calloc(1, sizeof(struct obj_update));
if (obj == NULL)
- return -1;
+ return NULL;
obj->ptr = ptr;
obj->error.lineno = h->error.lineno;
@@ -355,11 +394,12 @@ static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
list_add_tail(&obj->head, &h->obj_list);
h->obj_list_num++;
- return 0;
+ return obj;
}
-static int batch_table_add(struct nft_handle *h, enum obj_update_type type,
- struct nftnl_table *t)
+static struct obj_update *
+batch_table_add(struct nft_handle *h, enum obj_update_type type,
+ struct nftnl_table *t)
{
return batch_add(h, type, t);
}
@@ -367,18 +407,20 @@ static int batch_table_add(struct nft_handle *h, enum obj_update_type type,
static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c)
{
- return batch_add(h, type, c);
+ return batch_add(h, type, c) ? 0 : -1;
}
-static int batch_rule_add(struct nft_handle *h, enum obj_update_type type,
+static struct obj_update *
+batch_rule_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_rule *r)
{
return batch_add(h, type, r);
}
-struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
+const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = {
.name = "raw",
+ .type = NFT_TABLE_RAW,
.chains = {
{
.name = "PREROUTING",
@@ -396,6 +438,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
},
[NFT_TABLE_MANGLE] = {
.name = "mangle",
+ .type = NFT_TABLE_MANGLE,
.chains = {
{
.name = "PREROUTING",
@@ -431,6 +474,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
},
[NFT_TABLE_FILTER] = {
.name = "filter",
+ .type = NFT_TABLE_FILTER,
.chains = {
{
.name = "INPUT",
@@ -454,6 +498,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
},
[NFT_TABLE_SECURITY] = {
.name = "security",
+ .type = NFT_TABLE_SECURITY,
.chains = {
{
.name = "INPUT",
@@ -477,6 +522,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
},
[NFT_TABLE_NAT] = {
.name = "nat",
+ .type = NFT_TABLE_NAT,
.chains = {
{
.name = "PREROUTING",
@@ -508,9 +554,10 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
#include <linux/netfilter_arp.h>
-struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
+const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
[NFT_TABLE_FILTER] = {
.name = "filter",
+ .type = NFT_TABLE_FILTER,
.chains = {
{
.name = "INPUT",
@@ -530,9 +577,10 @@ struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
#include <linux/netfilter_bridge.h>
-struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
+const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
[NFT_TABLE_FILTER] = {
.name = "filter",
+ .type = NFT_TABLE_FILTER,
.chains = {
{
.name = "INPUT",
@@ -556,6 +604,7 @@ struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
},
[NFT_TABLE_NAT] = {
.name = "nat",
+ .type = NFT_TABLE_NAT,
.chains = {
{
.name = "PREROUTING",
@@ -579,13 +628,19 @@ struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
},
};
+static bool nft_table_initialized(const struct nft_handle *h,
+ enum nft_table_type type)
+{
+ return h->cache->table[type].initialized;
+}
+
static int nft_table_builtin_add(struct nft_handle *h,
- struct builtin_table *_t)
+ const struct builtin_table *_t)
{
struct nftnl_table *t;
int ret;
- if (_t->initialized)
+ if (nft_table_initialized(h, _t->type))
return 0;
t = nftnl_table_alloc();
@@ -594,14 +649,14 @@ static int nft_table_builtin_add(struct nft_handle *h,
nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name);
- ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t);
+ ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
return ret;
}
static struct nftnl_chain *
-nft_chain_builtin_alloc(struct builtin_table *table,
- struct builtin_chain *chain, int policy)
+nft_chain_builtin_alloc(const struct builtin_table *table,
+ const struct builtin_chain *chain, int policy)
{
struct nftnl_chain *c;
@@ -620,8 +675,8 @@ nft_chain_builtin_alloc(struct builtin_table *table,
}
static void nft_chain_builtin_add(struct nft_handle *h,
- struct builtin_table *table,
- struct builtin_chain *chain)
+ const struct builtin_table *table,
+ const struct builtin_chain *chain)
{
struct nftnl_chain *c;
@@ -630,32 +685,39 @@ static void nft_chain_builtin_add(struct nft_handle *h,
return;
batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
+ nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
}
-/* find if built-in table already exists */
-struct builtin_table *
-nft_table_builtin_find(struct nft_handle *h, const char *table)
+static const struct builtin_table *
+__nft_table_builtin_find(const struct builtin_table *tables, const char *table)
{
int i;
bool found = false;
for (i = 0; i < NFT_TABLE_MAX; i++) {
- if (h->tables[i].name == NULL)
+ if (tables[i].name == NULL)
continue;
- if (strcmp(h->tables[i].name, table) != 0)
+ if (strcmp(tables[i].name, table) != 0)
continue;
found = true;
break;
}
- return found ? &h->tables[i] : NULL;
+ return found ? &tables[i] : NULL;
+}
+
+/* find if built-in table already exists */
+const struct builtin_table *
+nft_table_builtin_find(struct nft_handle *h, const char *table)
+{
+ return __nft_table_builtin_find(h->tables, table);
}
/* find if built-in chain already exists */
-struct builtin_chain *
-nft_chain_builtin_find(struct builtin_table *t, const char *chain)
+const struct builtin_chain *
+nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
{
int i;
bool found = false;
@@ -671,17 +733,19 @@ nft_chain_builtin_find(struct builtin_table *t, const char *chain)
}
static void nft_chain_builtin_init(struct nft_handle *h,
- struct builtin_table *table)
+ const struct builtin_table *table)
{
- struct nftnl_chain_list *list = nft_chain_list_get(h);
+ struct nftnl_chain_list *list = nft_chain_list_get(h, table->name);
struct nftnl_chain *c;
int i;
+ if (!list)
+ return;
+
/* Initialize built-in chains if they don't exist yet */
for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
- c = nft_chain_list_find(list, table->name,
- table->chains[i].name);
+ c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
if (c != NULL)
continue;
@@ -691,13 +755,13 @@ static void nft_chain_builtin_init(struct nft_handle *h,
static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{
- struct builtin_table *t;
+ const struct builtin_table *t;
t = nft_table_builtin_find(h, table);
if (t == NULL)
return -1;
- if (t->initialized)
+ if (nft_table_initialized(h, t->type))
return 0;
if (nft_table_builtin_add(h, t) < 0)
@@ -705,7 +769,7 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
nft_chain_builtin_init(h, t);
- t->initialized = true;
+ h->cache->table[t->type].initialized = true;
return 0;
}
@@ -730,11 +794,12 @@ static int nft_restart(struct nft_handle *h)
return -1;
h->portid = mnl_socket_get_portid(h->nl);
+ nlbuffsiz = 0;
return 0;
}
-int nft_init(struct nft_handle *h, struct builtin_table *t)
+int nft_init(struct nft_handle *h, const struct builtin_table *t)
{
h->nl = mnl_socket_open(NETLINK_NETFILTER);
if (h->nl == NULL)
@@ -747,6 +812,7 @@ int nft_init(struct nft_handle *h, struct builtin_table *t)
h->portid = mnl_socket_get_portid(h->nl);
h->tables = t;
+ h->cache = &h->__cache[0];
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
@@ -756,60 +822,68 @@ int nft_init(struct nft_handle *h, struct builtin_table *t)
static int __flush_rule_cache(struct nftnl_rule *r, void *data)
{
- const char *tablename = data;
+ nftnl_rule_list_del(r);
+ nftnl_rule_free(r);
- if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) {
- nftnl_rule_list_del(r);
- nftnl_rule_free(r);
- }
+ return 0;
+}
+
+static void flush_rule_cache(struct nftnl_chain *c)
+{
+ nftnl_rule_foreach(c, __flush_rule_cache, NULL);
+}
+
+static int __flush_chain_cache(struct nftnl_chain *c, void *data)
+{
+ nftnl_chain_list_del(c);
+ nftnl_chain_free(c);
return 0;
}
-static void flush_rule_cache(struct nft_handle *h, const char *tablename)
+static int flush_cache(struct nft_cache *c, const struct builtin_table *tables,
+ const char *tablename)
{
- if (!h->rule_cache)
- return;
+ const struct builtin_table *table;
+ int i;
if (tablename) {
- nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache,
- (void *)tablename);
- } else {
- nftnl_rule_list_free(h->rule_cache);
- h->rule_cache = NULL;
+ table = __nft_table_builtin_find(tables, tablename);
+ if (!table || !c->table[table->type].chains)
+ return 0;
+ nftnl_chain_list_foreach(c->table[table->type].chains,
+ __flush_chain_cache, NULL);
+ return 0;
}
-}
-static int __flush_chain_cache(struct nftnl_chain *c, void *data)
-{
- const char *tablename = data;
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ if (tables[i].name == NULL)
+ continue;
+
+ if (!c->table[i].chains)
+ continue;
- if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) {
- nftnl_chain_list_del(c);
- nftnl_chain_free(c);
+ nftnl_chain_list_free(c->table[i].chains);
+ c->table[i].chains = NULL;
}
+ nftnl_table_list_free(c->tables);
+ c->tables = NULL;
- return 0;
+ return 1;
}
static void flush_chain_cache(struct nft_handle *h, const char *tablename)
{
- if (!h->chain_cache)
+ if (!h->have_cache)
return;
- if (tablename) {
- nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache,
- (void *)tablename);
- } else {
- nftnl_chain_list_free(h->chain_cache);
- h->chain_cache = NULL;
- }
+ if (flush_cache(h->cache, h->tables, tablename))
+ h->have_cache = false;
}
void nft_fini(struct nft_handle *h)
{
flush_chain_cache(h, NULL);
- flush_rule_cache(h, NULL);
mnl_socket_close(h->nl);
}
@@ -830,8 +904,8 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
const struct xt_counters *counters)
{
struct nftnl_chain *c;
- struct builtin_table *_t;
- struct builtin_chain *_c;
+ const struct builtin_table *_t;
+ const struct builtin_chain *_c;
_t = nft_table_builtin_find(h, table);
if (!_t) {
@@ -1103,37 +1177,11 @@ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
enum udata_type {
UDATA_TYPE_COMMENT,
+ UDATA_TYPE_EBTABLES_POLICY,
__UDATA_TYPE_MAX,
};
#define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
-int add_comment(struct nftnl_rule *r, const char *comment)
-{
- struct nftnl_udata_buf *udata;
- uint32_t len;
-
- if (nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len))
- return -EALREADY;
-
- udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
- if (!udata)
- return -ENOMEM;
-
- if (strnlen(comment, 255) == 255)
- return -ENOSPC;
-
- if (!nftnl_udata_put_strz(udata, UDATA_TYPE_COMMENT, comment))
- return -ENOMEM;
-
- nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
- nftnl_udata_buf_data(udata),
- nftnl_udata_buf_len(udata));
-
- nftnl_udata_buf_free(udata);
-
- return 0;
-}
-
static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
unsigned char *value = nftnl_udata_get(attr);
@@ -1146,6 +1194,8 @@ static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
if (value[len - 1] != '\0')
return -1;
break;
+ case UDATA_TYPE_EBTABLES_POLICY:
+ break;
default:
return 0;
}
@@ -1196,12 +1246,14 @@ err:
return NULL;
}
-static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h);
+static struct nftnl_chain *
+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, uint64_t handle, bool verbose)
+ void *data, struct nftnl_rule *ref, bool verbose)
{
+ struct nftnl_chain *c;
struct nftnl_rule *r;
int type;
@@ -1215,13 +1267,14 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
if (r == NULL)
return 0;
- if (handle > 0) {
- nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle);
+ if (ref) {
+ nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
+ nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
type = NFT_COMPAT_RULE_REPLACE;
} else
type = NFT_COMPAT_RULE_APPEND;
- if (batch_rule_add(h, type, r) < 0) {
+ if (batch_rule_add(h, type, r) == NULL) {
nftnl_rule_free(r);
return 0;
}
@@ -1229,10 +1282,17 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
- if (!nft_rule_list_get(h))
- return 0;
-
- nftnl_rule_list_add_tail(r, h->rule_cache);
+ if (ref) {
+ nftnl_chain_rule_insert_at(r, ref);
+ nftnl_chain_rule_del(r);
+ } else {
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
+ return 0;
+ }
+ nftnl_chain_rule_add_tail(r, c);
+ }
return 1;
}
@@ -1271,8 +1331,9 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
{
+ struct nft_handle *h = data;
+ const struct builtin_table *t;
struct nftnl_chain *c;
- struct nftnl_chain_list *list = data;
c = nftnl_chain_alloc();
if (c == NULL)
@@ -1281,7 +1342,12 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
goto out;
- nftnl_chain_list_add_tail(c, list);
+ t = nft_table_builtin_find(h,
+ nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
+ if (!t)
+ goto out;
+
+ nftnl_chain_list_add_tail(c, h->cache->table[t->type].chains);
return MNL_CB_OK;
out:
@@ -1290,35 +1356,289 @@ err:
return MNL_CB_OK;
}
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h)
+static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_table *t;
+ struct nftnl_table_list *list = data;
+
+ t = nftnl_table_alloc();
+ if (t == NULL)
+ goto err;
+
+ if (nftnl_table_nlmsg_parse(nlh, t) < 0)
+ goto out;
+
+ nftnl_table_list_add_tail(t, list);
+
+ return MNL_CB_OK;
+out:
+ nftnl_table_free(t);
+err:
+ return MNL_CB_OK;
+}
+
+static int fetch_table_cache(struct nft_handle *h)
{
char buf[16536];
struct nlmsghdr *nlh;
- struct nftnl_chain_list *list;
+ struct nftnl_table_list *list;
int ret;
- if (h->chain_cache)
- return h->chain_cache;
-retry:
- list = nftnl_chain_list_alloc();
- if (list == NULL) {
- errno = ENOMEM;
- return NULL;
+ list = nftnl_table_list_alloc();
+ if (list == NULL)
+ return 0;
+
+ nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
+ NLM_F_DUMP, h->seq);
+
+ ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
+
+ h->cache->tables = list;
+
+ return 1;
+}
+
+static int fetch_chain_cache(struct nft_handle *h)
+{
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ int i, ret;
+
+ 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->table[type].chains = nftnl_chain_list_alloc();
+ if (!h->cache->table[type].chains)
+ return -1;
}
nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
NLM_F_DUMP, h->seq);
- ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list);
- if (ret < 0 && errno == EINTR) {
+ ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h);
+ if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
- nftnl_chain_list_free(list);
+
+ return ret;
+}
+
+static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
+{
+ const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
+ const void *data;
+ uint32_t len;
+
+ if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA))
+ return false;
+
+ data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
+ if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0)
+ return NULL;
+
+ if (!tb[UDATA_TYPE_EBTABLES_POLICY] ||
+ nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1)
+ return false;
+
+ return true;
+}
+
+static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
+{
+ struct nftnl_rule *r = NULL, *last;
+ struct nftnl_rule_iter *iter;
+
+ iter = nftnl_rule_iter_create(c);
+ if (!iter)
+ return NULL;
+
+ do {
+ last = r;
+ r = nftnl_rule_iter_next(iter);
+ } while (r);
+ nftnl_rule_iter_destroy(iter);
+
+ return last;
+}
+
+static void nft_bridge_chain_postprocess(struct nft_handle *h,
+ struct nftnl_chain *c)
+{
+ struct nftnl_rule *last = nft_chain_last_rule(c);
+ struct nftnl_expr_iter *iter;
+ struct nftnl_expr *expr;
+ int verdict;
+
+ if (!last || !nft_rule_is_policy_rule(last))
+ return;
+
+ iter = nftnl_expr_iter_create(last);
+ if (!iter)
+ return;
+
+ expr = nftnl_expr_iter_next(iter);
+ if (!expr ||
+ strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
+ goto out_iter;
+
+ expr = nftnl_expr_iter_next(iter);
+ if (!expr ||
+ strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
+ !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
+ goto out_iter;
+
+ verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
+ switch (verdict) {
+ case NF_ACCEPT:
+ case NF_DROP:
+ break;
+ default:
+ goto out_iter;
+ }
+
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
+ if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
+ fprintf(stderr, "Failed to delete old policy rule\n");
+ nftnl_chain_rule_del(last);
+out_iter:
+ nftnl_expr_iter_destroy(iter);
+}
+
+static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_chain *c = data;
+ struct nftnl_rule *r;
+
+ r = nftnl_rule_alloc();
+ if (r == NULL)
+ return MNL_CB_OK;
+
+ if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
+ nftnl_rule_free(r);
+ return MNL_CB_OK;
+ }
+
+ nftnl_chain_rule_add_tail(r, c);
+ return MNL_CB_OK;
+}
+
+static int nft_rule_list_update(struct nftnl_chain *c, void *data)
+{
+ struct nft_handle *h = data;
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ struct nftnl_rule *rule;
+ int ret;
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -1;
+
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
+ nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
+ nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+
+ nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
+ NLM_F_DUMP, h->seq);
+ nftnl_rule_nlmsg_build_payload(nlh, rule);
+
+ ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
+
+ nftnl_rule_free(rule);
+
+ if (h->family == NFPROTO_BRIDGE)
+ nft_bridge_chain_postprocess(h, c);
+
+ return 0;
+}
+
+static int fetch_rule_cache(struct nft_handle *h)
+{
+ int i;
+
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ if (nftnl_chain_list_foreach(h->cache->table[type].chains,
+ nft_rule_list_update, h))
+ return -1;
+ }
+ return 0;
+}
+
+static void __nft_build_cache(struct nft_handle *h)
+{
+ uint32_t genid_start, genid_stop;
+
+retry:
+ mnl_genid_get(h, &genid_start);
+ fetch_chain_cache(h);
+ fetch_rule_cache(h);
+ h->have_cache = true;
+ mnl_genid_get(h, &genid_stop);
+
+ if (genid_start != genid_stop) {
+ flush_chain_cache(h, NULL);
goto retry;
}
- h->chain_cache = list;
+ h->nft_genid = genid_start;
+}
- return list;
+void nft_build_cache(struct nft_handle *h)
+{
+ if (!h->have_cache)
+ __nft_build_cache(h);
+}
+
+static void __nft_flush_cache(struct nft_handle *h)
+{
+ if (!h->cache_index) {
+ h->cache_index++;
+ h->cache = &h->__cache[h->cache_index];
+ } else {
+ flush_chain_cache(h, NULL);
+ }
+}
+
+static void nft_rebuild_cache(struct nft_handle *h)
+{
+ if (h->have_cache)
+ __nft_flush_cache(h);
+
+ __nft_build_cache(h);
+}
+
+static void nft_release_cache(struct nft_handle *h)
+{
+ if (h->cache_index)
+ flush_cache(&h->__cache[0], h->tables, NULL);
+}
+
+struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
+ const char *table)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return NULL;
+
+ nft_build_cache(h);
+
+ return h->cache->table[t->type].chains;
}
static const char *policy_name[NF_ACCEPT+1] = {
@@ -1326,8 +1646,7 @@ static const char *policy_name[NF_ACCEPT+1] = {
[NF_ACCEPT] = "ACCEPT",
};
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
- const char *table)
+int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
{
struct nftnl_chain_list_iter *iter;
struct nft_family_ops *ops;
@@ -1341,24 +1660,28 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
c = nftnl_chain_list_iter_next(iter);
while (c != NULL) {
- const char *chain_table =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
const char *policy = NULL;
- if (strcmp(table, chain_table) != 0)
- goto next;
-
if (nft_chain_builtin(c)) {
uint32_t pol = NF_ACCEPT;
if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY))
pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
policy = policy_name[pol];
+ } else if (h->family == NFPROTO_BRIDGE) {
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
+ uint32_t pol;
+
+ pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
+ policy = policy_name[pol];
+ } else {
+ policy = "RETURN";
+ }
}
if (ops->save_chain)
ops->save_chain(c, policy);
-next:
+
c = nftnl_chain_list_iter_next(iter);
}
@@ -1367,101 +1690,66 @@ next:
return 1;
}
-static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
+static int nft_chain_save_rules(struct nft_handle *h,
+ struct nftnl_chain *c, unsigned int format)
{
+ struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
- struct nftnl_rule_list *list = data;
-
- r = nftnl_rule_alloc();
- if (r == NULL)
- goto err;
-
- if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
- goto out;
-
- nftnl_rule_list_add_tail(r, list);
-
- return MNL_CB_OK;
-out:
- nftnl_rule_free(r);
- nftnl_rule_list_free(list);
-err:
- return MNL_CB_OK;
-}
-static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
-{
- char buf[16536];
- struct nlmsghdr *nlh;
- struct nftnl_rule_list *list;
- int ret;
-
- if (h->rule_cache)
- return h->rule_cache;
-
-retry:
- list = nftnl_rule_list_alloc();
- if (list == NULL)
- return 0;
-
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
- NLM_F_DUMP, h->seq);
-
- ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
- if (ret < 0) {
- if (errno == EINTR) {
- assert(nft_restart(h) >= 0);
- nftnl_rule_list_free(list);
- goto retry;
- }
+ iter = nftnl_rule_iter_create(c);
+ if (iter == NULL)
+ return 1;
- nftnl_rule_list_free(list);
- return NULL;
+ r = nftnl_rule_iter_next(iter);
+ while (r != NULL) {
+ nft_rule_print_save(r, NFT_RULE_APPEND, format);
+ r = nftnl_rule_iter_next(iter);
}
- h->rule_cache = list;
- return list;
+ nftnl_rule_iter_destroy(iter);
+ return 0;
}
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
{
- struct nftnl_rule_list *list;
- struct nftnl_rule_list_iter *iter;
- struct nftnl_rule *r;
+ struct nftnl_chain_list_iter *iter;
+ struct nftnl_chain_list *list;
+ struct nftnl_chain *c;
+ int ret = 0;
- list = nft_rule_list_get(h);
- if (list == NULL)
+ list = nft_chain_list_get(h, table);
+ if (!list)
return 0;
- iter = nftnl_rule_list_iter_create(list);
- if (iter == NULL)
+ iter = nftnl_chain_list_iter_create(list);
+ if (!iter)
return 0;
- r = nftnl_rule_list_iter_next(iter);
- while (r != NULL) {
- const char *rule_table =
- nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
-
- if (strcmp(table, rule_table) != 0)
- goto next;
-
- nft_rule_print_save(r, NFT_RULE_APPEND, format);
+ c = nftnl_chain_list_iter_next(iter);
+ while (c) {
+ ret = nft_chain_save_rules(h, c, format);
+ if (ret != 0)
+ break;
-next:
- r = nftnl_rule_list_iter_next(iter);
+ c = nftnl_chain_list_iter_next(iter);
}
- nftnl_rule_list_iter_destroy(iter);
+ nftnl_chain_list_iter_destroy(iter);
/* the core expects 1 for success and 0 for error */
- return 1;
+ return ret == 0 ? 1 : 0;
}
static void
-__nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
+__nft_rule_flush(struct nft_handle *h, const char *table,
+ const char *chain, bool verbose, bool implicit)
{
+ struct obj_update *obj;
struct nftnl_rule *r;
+ if (verbose)
+ fprintf(stdout, "Flushing chain `%s'\n", chain);
+
r = nftnl_rule_alloc();
if (r == NULL)
return;
@@ -1469,51 +1757,13 @@ __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
- if (batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r) < 0)
+ obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
+ if (!obj) {
nftnl_rule_free(r);
-}
-
-struct chain_user_flush_data {
- struct nft_handle *handle;
- const char *table;
- const char *chain;
-};
-
-static int __nft_chain_user_flush(struct nftnl_chain *c, void *data)
-{
- const char *table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- struct chain_user_flush_data *d = data;
- struct nft_handle *h = d->handle;
- const char *table = d->table;
- const char *chain = d->chain;
-
- if (strcmp(table, table_name) != 0)
- return 0;
-
- if (strcmp(chain, chain_name) != 0)
- return 0;
-
- if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM))
- __nft_rule_flush(h, table, chain);
-
- return 0;
-}
-
-int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list,
- const char *table, const char *chain)
-{
- struct chain_user_flush_data d = {
- .handle = h,
- .table = table,
- .chain = chain,
- };
-
- nft_fn = nft_chain_user_flush;
-
- nftnl_chain_list_foreach(list, __nft_chain_user_flush, &d);
+ return;
+ }
- return 1;
+ obj->implicit = implicit;
}
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
@@ -1529,12 +1779,22 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
nft_fn = nft_rule_flush;
- list = nft_chain_list_get(h);
+ list = nft_chain_list_get(h, table);
if (list == NULL) {
ret = 1;
goto err;
}
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c)
+ return 0;
+
+ __nft_rule_flush(h, table, chain, verbose, false);
+ flush_rule_cache(c);
+ return 1;
+ }
+
iter = nftnl_chain_list_iter_create(list);
if (iter == NULL) {
ret = 1;
@@ -1543,29 +1803,14 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
c = nftnl_chain_list_iter_next(iter);
while (c != NULL) {
- const char *table_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
const char *chain_name =
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- if (strcmp(table, table_name) != 0)
- goto next;
-
- if (chain != NULL && strcmp(chain, chain_name) != 0)
- goto next;
-
- if (verbose)
- fprintf(stdout, "Flushing chain `%s'\n", chain_name);
-
- __nft_rule_flush(h, table_name, chain_name);
-
- if (chain != NULL)
- break;
-next:
+ __nft_rule_flush(h, table, chain_name, verbose, false);
+ flush_rule_cache(c);
c = nftnl_chain_list_iter_next(iter);
}
nftnl_chain_list_iter_destroy(iter);
- flush_rule_cache(h, table);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1573,6 +1818,7 @@ err:
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
{
+ struct nftnl_chain_list *list;
struct nftnl_chain *c;
int ret;
@@ -1582,125 +1828,138 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
+ if (nft_chain_exists(h, table, chain)) {
+ errno = EEXIST;
+ return 0;
+ }
+
c = nftnl_chain_alloc();
if (c == NULL)
return 0;
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
+ if (h->family == NFPROTO_BRIDGE)
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
- nft_chain_list_get(h);
-
- nftnl_chain_list_add(c, h->chain_cache);
+ list = nft_chain_list_get(h, table);
+ if (list)
+ nftnl_chain_list_add(c, list);
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
-/* From linux/netlink.h */
-#ifndef NLM_F_NONREC
-#define NLM_F_NONREC 0x100 /* Do not delete recursively */
-#endif
-
-int nft_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose)
+int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{
struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
struct nftnl_chain *c;
- int ret = 0;
- int deleted_ctr = 0;
-
- nft_fn = nft_chain_user_del;
+ bool created = false;
+ int ret;
- list = nft_chain_list_get(h);
- if (list == NULL)
- goto err;
+ c = nft_chain_find(h, table, chain);
+ if (c) {
+ /* Apparently -n still flushes existing user defined
+ * chains that are redefined.
+ */
+ if (h->noflush)
+ __nft_rule_flush(h, table, chain, false, true);
+ } else {
+ c = nftnl_chain_alloc();
+ if (!c)
+ return -1;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- goto err;
+ nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
+ nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
+ created = true;
+ }
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- const char *table_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ if (h->family == NFPROTO_BRIDGE)
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
- /* don't delete built-in chain */
- if (nft_chain_builtin(c))
- goto next;
+ if (!created)
+ return 0;
- if (strcmp(table, table_name) != 0)
- goto next;
+ ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
- if (chain != NULL && strcmp(chain, chain_name) != 0)
- goto next;
+ list = nft_chain_list_get(h, table);
+ if (list)
+ nftnl_chain_list_add(c, list);
- if (verbose)
- fprintf(stdout, "Deleting chain `%s'\n", chain);
+ return ret;
+}
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
+/* From linux/netlink.h */
+#ifndef NLM_F_NONREC
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+#endif
- if (ret < 0)
- break;
+struct chain_user_del_data {
+ struct nft_handle *handle;
+ bool verbose;
+ int builtin_err;
+};
- deleted_ctr++;
- nftnl_chain_list_del(c);
+static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
+{
+ struct chain_user_del_data *d = data;
+ struct nft_handle *h = d->handle;
+ int ret;
- if (chain != NULL)
- break;
-next:
- c = nftnl_chain_list_iter_next(iter);
- }
+ /* don't delete built-in chain */
+ if (nft_chain_builtin(c))
+ return d->builtin_err;
- nftnl_chain_list_iter_destroy(iter);
-err:
+ if (d->verbose)
+ fprintf(stdout, "Deleting chain `%s'\n",
+ nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
- /* chain not found */
- if (chain != NULL && deleted_ctr == 0) {
- ret = -1;
- errno = ENOENT;
- }
+ /* 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);
+ if (ret)
+ return -1;
- /* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ nftnl_chain_list_del(c);
+ return 0;
}
-struct nftnl_chain *
-nft_chain_list_find(struct nftnl_chain_list *list,
- const char *table, const char *chain)
+int nft_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
{
- struct nftnl_chain_list_iter *iter;
+ struct chain_user_del_data d = {
+ .handle = h,
+ .verbose = verbose,
+ };
+ struct nftnl_chain_list *list;
struct nftnl_chain *c;
+ int ret = 0;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return NULL;
-
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- const char *table_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
-
- if (strcmp(table, table_name) != 0)
- goto next;
+ nft_fn = nft_chain_user_del;
- if (strcmp(chain, chain_name) != 0)
- goto next;
+ list = nft_chain_list_get(h, table);
+ if (list == NULL)
+ return 0;
- nftnl_chain_list_iter_destroy(iter);
- return c;
-next:
- c = nftnl_chain_list_iter_next(iter);
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c) {
+ errno = ENOENT;
+ return 0;
+ }
+ d.builtin_err = -2;
+ ret = __nft_chain_user_del(c, &d);
+ if (ret == -2)
+ errno = EINVAL;
+ goto out;
}
- nftnl_chain_list_iter_destroy(iter);
- return NULL;
+
+ ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d);
+out:
+ /* the core expects 1 for success and 0 for error */
+ return ret == 0 ? 1 : 0;
}
static struct nftnl_chain *
@@ -1708,17 +1967,17 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
{
struct nftnl_chain_list *list;
- list = nft_chain_list_get(h);
+ list = nft_chain_list_get(h, table);
if (list == NULL)
return NULL;
- return nft_chain_list_find(list, table, chain);
+ return nftnl_chain_list_lookup_byname(list, chain);
}
bool nft_chain_exists(struct nft_handle *h,
const char *table, const char *chain)
{
- struct builtin_table *t = nft_table_builtin_find(h, table);
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
/* xtables does not support custom tables */
if (!t)
@@ -1737,7 +1996,12 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
uint64_t handle;
int ret;
- nft_fn = nft_chain_user_add;
+ nft_fn = nft_chain_user_rename;
+
+ if (nft_chain_exists(h, table, newname)) {
+ errno = EEXIST;
+ return 0;
+ }
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
@@ -1769,56 +2033,17 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return ret == 0 ? 1 : 0;
}
-static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
-{
- struct nftnl_table *t;
- struct nftnl_table_list *list = data;
-
- t = nftnl_table_alloc();
- if (t == NULL)
- goto err;
-
- if (nftnl_table_nlmsg_parse(nlh, t) < 0)
- goto out;
-
- nftnl_table_list_add_tail(t, list);
-
- return MNL_CB_OK;
-out:
- nftnl_table_free(t);
-err:
- return MNL_CB_OK;
-}
-
static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
{
- char buf[16536];
- struct nlmsghdr *nlh;
- struct nftnl_table_list *list;
- int ret;
+ nft_build_cache(h);
-retry:
- list = nftnl_table_list_alloc();
- if (list == NULL)
- return 0;
-
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
- NLM_F_DUMP, h->seq);
-
- ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
- if (ret < 0 && errno == EINTR) {
- assert(nft_restart(h) >= 0);
- nftnl_table_list_free(list);
- goto retry;
- }
-
- return list;
+ return h->cache->tables;
}
bool nft_table_find(struct nft_handle *h, const char *tablename)
{
- struct nftnl_table_list *list;
struct nftnl_table_list_iter *iter;
+ struct nftnl_table_list *list;
struct nftnl_table *t;
bool ret = false;
@@ -1844,7 +2069,6 @@ bool nft_table_find(struct nft_handle *h, const char *tablename)
}
nftnl_table_list_iter_destroy(iter);
- nftnl_table_list_free(list);
err:
return ret;
@@ -1877,13 +2101,13 @@ int nft_for_each_table(struct nft_handle *h,
}
nftnl_table_list_iter_destroy(iter);
- nftnl_table_list_free(list);
return 0;
}
-static int __nft_table_flush(struct nft_handle *h, const char *table)
+static int __nft_table_flush(struct nft_handle *h, const char *table, bool exists)
{
- struct builtin_table *_t;
+ const struct builtin_table *_t;
+ struct obj_update *obj;
struct nftnl_table *t;
t = nftnl_table_alloc();
@@ -1892,14 +2116,20 @@ static int __nft_table_flush(struct nft_handle *h, const char *table)
nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
- batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
+ obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
+ if (!obj) {
+ nftnl_table_free(t);
+ return -1;
+ }
+
+ if (!exists)
+ obj->skip = 1;
_t = nft_table_builtin_find(h, table);
assert(_t);
- _t->initialized = false;
+ h->cache->table[_t->type].initialized = false;
flush_chain_cache(h, table);
- flush_rule_cache(h, table);
return 0;
}
@@ -1909,6 +2139,7 @@ int nft_table_flush(struct nft_handle *h, const char *table)
struct nftnl_table_list_iter *iter;
struct nftnl_table_list *list;
struct nftnl_table *t;
+ bool exists = false;
int ret = 0;
nft_fn = nft_table_flush;
@@ -1930,26 +2161,17 @@ int nft_table_flush(struct nft_handle *h, const char *table)
const char *table_name =
nftnl_table_get_str(t, NFTNL_TABLE_NAME);
- if (strcmp(table_name, table) != 0)
- goto next;
+ if (strcmp(table_name, table) == 0) {
+ exists = true;
+ break;
+ }
- ret = __nft_table_flush(h, table);
- if (ret < 0)
- goto err_table_iter;
-next:
t = nftnl_table_list_iter_next(iter);
}
- if (!h->rule_cache) {
- h->rule_cache = nftnl_rule_list_alloc();
- if (h->rule_cache == NULL)
- return -1;
- }
-
-err_table_iter:
+ ret = __nft_table_flush(h, table, exists);
nftnl_table_list_iter_destroy(iter);
err_table_list:
- nftnl_table_list_free(list);
err_out:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1961,15 +2183,14 @@ void nft_table_new(struct nft_handle *h, const char *table)
nft_xt_builtin_init(h, table);
}
-static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list,
- struct nftnl_rule *r)
+static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
{
- int ret;
+ struct obj_update *obj;
nftnl_rule_list_del(r);
- ret = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
- if (ret < 0) {
+ obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
+ if (!obj) {
nftnl_rule_free(r);
return -1;
}
@@ -1977,48 +2198,29 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list,
}
static struct nftnl_rule *
-nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list,
- const char *chain, const char *table, void *data, int rulenum)
+nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
{
struct nftnl_rule *r;
- struct nftnl_rule_list_iter *iter;
- int rule_ctr = 0;
+ struct nftnl_rule_iter *iter;
bool found = false;
- iter = nftnl_rule_list_iter_create(list);
+ if (rulenum >= 0)
+ /* Delete by rule number case */
+ return nftnl_rule_lookup_byindex(c, rulenum);
+
+ iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return 0;
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- const char *rule_table =
- nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
- const char *rule_chain =
- nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
-
- if (strcmp(table, rule_table) != 0 ||
- strcmp(chain, rule_chain) != 0) {
- DEBUGP("different chain / table\n");
- goto next;
- }
-
- if (rulenum >= 0) {
- /* Delete by rule number case */
- if (rule_ctr == rulenum) {
- found = true;
- break;
- }
- } else {
- found = h->ops->rule_find(h->ops, r, data);
- if (found)
- break;
- }
- rule_ctr++;
-next:
- r = nftnl_rule_list_iter_next(iter);
+ found = h->ops->rule_find(h->ops, r, data);
+ if (found)
+ break;
+ r = nftnl_rule_iter_next(iter);
}
- nftnl_rule_list_iter_destroy(iter);
+ nftnl_rule_iter_destroy(iter);
return found ? r : NULL;
}
@@ -2026,42 +2228,46 @@ next:
int nft_rule_check(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose)
{
- struct nftnl_rule_list *list;
+ struct nftnl_chain *c;
struct nftnl_rule *r;
nft_fn = nft_rule_check;
- list = nft_rule_list_get(h);
- if (list == NULL)
- return 0;
+ c = nft_chain_find(h, table, chain);
+ if (!c)
+ goto fail_enoent;
+
+ r = nft_rule_find(h, c, data, -1);
+ if (r == NULL)
+ goto fail_enoent;
- r = nft_rule_find(h, list, chain, table, data, -1);
- if (r == NULL) {
- errno = ENOENT;
- return 0;
- }
if (verbose)
h->ops->print_rule(r, 0, FMT_PRINT_RULE);
return 1;
+fail_enoent:
+ errno = ENOENT;
+ return 0;
}
int nft_rule_delete(struct nft_handle *h, const char *chain,
const char *table, void *data, bool verbose)
{
int ret = 0;
+ struct nftnl_chain *c;
struct nftnl_rule *r;
- struct nftnl_rule_list *list;
nft_fn = nft_rule_delete;
- list = nft_rule_list_get(h);
- if (list == NULL)
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
- r = nft_rule_find(h, list, chain, table, data, -1);
+ r = nft_rule_find(h, c, data, -1);
if (r != NULL) {
- ret =__nft_rule_del(h, list, r);
+ ret =__nft_rule_del(h, r);
if (ret < 0)
errno = ENOMEM;
if (verbose)
@@ -2075,18 +2281,32 @@ 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,
- uint64_t handle, bool verbose)
+ 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 (handle > 0)
- nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
+ if (ref) {
+ ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
+ if (ref_id > 0) {
+ nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id);
+ DEBUGP("adding after rule handle %"PRIu64"\n", ref_id);
+ } else {
+ ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID);
+ if (!ref_id) {
+ ref_id = ++h->rule_id;
+ nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id);
+ }
+ nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id);
+ DEBUGP("adding after rule ID %"PRIu64"\n", ref_id);
+ }
+ }
- if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) {
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
nftnl_rule_free(r);
return NULL;
}
@@ -2100,9 +2320,8 @@ 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)
{
- struct nftnl_rule *r, *new_rule;
- struct nftnl_rule_list *list;
- uint64_t handle = 0;
+ struct nftnl_rule *r = NULL, *new_rule;
+ struct nftnl_chain *c;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
@@ -2110,40 +2329,36 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
nft_fn = nft_rule_insert;
- if (rulenum > 0) {
- list = nft_rule_list_get(h);
- if (list == NULL)
- goto err;
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
+ goto err;
+ }
- r = nft_rule_find(h, list, chain, table, data, rulenum);
+ if (rulenum > 0) {
+ r = nft_rule_find(h, c, data, rulenum);
if (r == NULL) {
/* special case: iptables allows to insert into
* rule_count + 1 position.
*/
- r = nft_rule_find(h, list, chain, table, data,
- rulenum - 1);
+ r = nft_rule_find(h, c, data, rulenum - 1);
if (r != NULL)
return nft_rule_append(h, chain, table, data,
- 0, verbose);
+ NULL, verbose);
- errno = ENOENT;
+ errno = E2BIG;
goto err;
}
-
- handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
- DEBUGP("adding after rule handle %"PRIu64"\n", handle);
- } else {
- nft_rule_list_get(h);
}
- new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
+ new_rule = nft_rule_add(h, chain, table, data, r, verbose);
if (!new_rule)
goto err;
- if (handle)
- nftnl_rule_list_insert_at(new_rule, r);
+ if (r)
+ nftnl_chain_rule_insert_at(new_rule, r);
else
- nftnl_rule_list_add(new_rule, h->rule_cache);
+ nftnl_chain_rule_add(new_rule, c);
return 1;
err:
@@ -2154,23 +2369,25 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
const char *table, int rulenum, bool verbose)
{
int ret = 0;
+ struct nftnl_chain *c;
struct nftnl_rule *r;
- struct nftnl_rule_list *list;
nft_fn = nft_rule_delete_num;
- list = nft_rule_list_get(h);
- if (list == NULL)
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
- r = nft_rule_find(h, list, chain, table, NULL, rulenum);
+ r = nft_rule_find(h, c, NULL, rulenum);
if (r != NULL) {
DEBUGP("deleting rule by number %d\n", rulenum);
- ret = __nft_rule_del(h, list, r);
+ ret = __nft_rule_del(h, r);
if (ret < 0)
errno = ENOMEM;
} else
- errno = ENOENT;
+ errno = E2BIG;
return ret;
}
@@ -2179,117 +2396,106 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
const char *table, void *data, int rulenum, bool verbose)
{
int ret = 0;
+ struct nftnl_chain *c;
struct nftnl_rule *r;
- struct nftnl_rule_list *list;
nft_fn = nft_rule_replace;
- list = nft_rule_list_get(h);
- if (list == NULL)
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
- r = nft_rule_find(h, list, chain, table, data, rulenum);
+ r = nft_rule_find(h, c, data, rulenum);
if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
- nftnl_rule_list_del(r);
-
- ret = nft_rule_append(h, chain, table, data,
- nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
- verbose);
+ ret = nft_rule_append(h, chain, table, data, r, verbose);
} else
- errno = ENOENT;
+ errno = E2BIG;
return ret;
}
static int
-__nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
+__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
int rulenum, unsigned int format,
void (*cb)(struct nftnl_rule *r, unsigned int num,
unsigned int format))
{
- struct nftnl_rule_list *list;
- struct nftnl_rule_list_iter *iter;
+ struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
int rule_ctr = 0;
- list = nft_rule_list_get(h);
- if (list == NULL)
- return 0;
+ if (rulenum > 0) {
+ r = nftnl_rule_lookup_byindex(c, rulenum - 1);
+ if (!r)
+ /* iptables-legacy returns 0 when listing for
+ * valid chain but invalid rule number
+ */
+ return 1;
+ cb(r, rulenum, format);
+ return 1;
+ }
- iter = nftnl_rule_list_iter_create(list);
+ iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return 0;
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- const char *rule_table =
- nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
- const char *rule_chain =
- nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
-
- if (strcmp(table, rule_table) != 0 ||
- strcmp(chain, rule_chain) != 0)
- goto next;
-
- rule_ctr++;
-
- if (rulenum > 0 && rule_ctr != rulenum) {
- /* List by rule number case */
- goto next;
- }
-
- cb(r, rule_ctr, format);
- if (rulenum > 0)
- break;
-
-next:
- r = nftnl_rule_list_iter_next(iter);
+ cb(r, ++rule_ctr, format);
+ r = nftnl_rule_iter_next(iter);
}
- nftnl_rule_list_iter_destroy(iter);
+ nftnl_rule_iter_destroy(iter);
return 1;
}
-static int nft_rule_count(struct nft_handle *h,
- const char *chain, const char *table)
+static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
{
- struct nftnl_rule_list_iter *iter;
- struct nftnl_rule_list *list;
+ struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
int rule_ctr = 0;
- list = nft_rule_list_get(h);
- if (list == NULL)
- return 0;
-
- iter = nftnl_rule_list_iter_create(list);
+ iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return 0;
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- const char *rule_table =
- nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
- const char *rule_chain =
- nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
-
- if (strcmp(table, rule_table) != 0 ||
- strcmp(chain, rule_chain) != 0)
- goto next;
-
rule_ctr++;
-next:
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
}
- nftnl_rule_list_iter_destroy(iter);
+ nftnl_rule_iter_destroy(iter);
return rule_ctr;
}
+static void __nft_print_header(struct nft_handle *h,
+ const struct nft_family_ops *ops,
+ struct nftnl_chain *c, unsigned int format)
+{
+ const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
+ uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
+ uint32_t entries = nft_rule_count(h, c);
+ struct xt_counters ctrs = {
+ .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
+ .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
+ };
+ const char *pname = NULL;
+
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
+ pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
+
+ ops->print_header(format, chain_name, pname,
+ &ctrs, basechain, refs - entries, entries);
+}
+
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format)
{
@@ -2300,16 +2506,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
bool found = false;
/* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
+ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
- /* Force table and chain creation, otherwise first iptables -L
- * lists no table/chains.
- */
- if (!list_empty(&h->obj_list)) {
- nft_commit(h);
- flush_chain_cache(h, NULL);
- }
- }
ops = nft_family_ops_lookup(h->family);
@@ -2318,75 +2516,43 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
return 0;
}
- if (chain && rulenum) {
- __nft_rule_list(h, chain, table,
- rulenum, format, ops->print_rule);
+ list = nft_chain_list_get(h, table);
+ if (!list)
+ return 0;
+
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c)
+ return 0;
+
+ if (!rulenum) {
+ if (ops->print_table_header)
+ ops->print_table_header(table);
+ __nft_print_header(h, ops, c, format);
+ }
+ __nft_rule_list(h, c, rulenum, format, ops->print_rule);
return 1;
}
- list = nft_chain_list_get(h);
-
iter = nftnl_chain_list_iter_create(list);
if (iter == NULL)
- goto err;
+ return 0;
- if (!chain && ops->print_table_header)
+ if (ops->print_table_header)
ops->print_table_header(table);
c = nftnl_chain_list_iter_next(iter);
while (c != NULL) {
- const char *chain_table =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- uint32_t policy =
- nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
- uint32_t refs =
- nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
- struct xt_counters ctrs = {
- .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
- .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
- };
- bool basechain = false;
- uint32_t entries;
-
- if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
- basechain = true;
-
- if (strcmp(table, chain_table) != 0)
- goto next;
- if (chain) {
- if (strcmp(chain, chain_name) != 0)
- goto next;
- else if (ops->print_table_header)
- ops->print_table_header(table);
- }
-
if (found)
printf("\n");
- entries = nft_rule_count(h, chain_name, table);
- ops->print_header(format, chain_name, policy_name[policy],
- &ctrs, basechain, refs - entries, entries);
-
- __nft_rule_list(h, chain_name, table,
- rulenum, format, ops->print_rule);
+ __nft_print_header(h, ops, c, format);
+ __nft_rule_list(h, c, rulenum, format, ops->print_rule);
found = true;
-
- /* we printed the chain we wanted, stop processing. */
- if (chain)
- break;
-
-next:
c = nftnl_chain_list_iter_next(iter);
}
-
nftnl_chain_list_iter_destroy(iter);
-err:
- if (chain && !found)
- return 0;
-
return 1;
}
@@ -2396,50 +2562,44 @@ list_save(struct nftnl_rule *r, unsigned int num, unsigned int format)
nft_rule_print_save(r, NFT_RULE_APPEND, format);
}
-static int
-nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
- const char *table, struct nftnl_chain_list *list,
- int counters)
+static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
{
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain *c;
+ const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
+ int *counters = data;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
+ if (!nft_chain_builtin(c)) {
+ printf("-N %s\n", chain_name);
return 0;
+ }
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- const char *chain_table =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- uint32_t policy =
- nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
+ /* this is a base chain */
- if (strcmp(table, chain_table) != 0 ||
- (chain && strcmp(chain, chain_name) != 0))
- goto next;
+ printf("-P %s %s", chain_name, policy_name[policy]);
+ if (*counters)
+ printf(" -c %"PRIu64" %"PRIu64,
+ nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
+ nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
+ printf("\n");
+ return 0;
+}
- /* this is a base chain */
- if (nft_chain_builtin(c)) {
- printf("-P %s %s", chain_name, policy_name[policy]);
-
- if (counters) {
- printf(" -c %"PRIu64" %"PRIu64"\n",
- nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
- nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
- } else
- printf("\n");
- } else {
- printf("-N %s\n", chain_name);
- }
-next:
- c = nftnl_chain_list_iter_next(iter);
- }
+static int
+nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
+ struct nftnl_chain_list *list, int counters)
+{
+ struct nftnl_chain *c;
- nftnl_chain_list_iter_destroy(iter);
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c)
+ return 0;
+ __nftnl_rule_list_chain_save(c, &counters);
+ return 1;
+ }
+
+ nftnl_chain_list_foreach(list, __nftnl_rule_list_chain_save, &counters);
return 1;
}
@@ -2453,62 +2613,46 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
int ret = 0;
/* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
+ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
nft_xt_builtin_init(h, table);
- /* Force table and chain creation, otherwise first iptables -L
- * lists no table/chains.
- */
- if (!list_empty(&h->obj_list)) {
- nft_commit(h);
- flush_chain_cache(h, NULL);
- }
- }
if (!nft_is_table_compatible(h, table)) {
xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
return 0;
}
- list = nft_chain_list_get(h);
+ list = nft_chain_list_get(h, table);
+ if (!list)
+ return 0;
/* Dump policies and custom chains first */
if (!rulenum)
- nftnl_rule_list_chain_save(h, chain, table, list, counters);
-
- /* Now dump out rules in this table */
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- goto err;
+ nftnl_rule_list_chain_save(h, chain, list, counters);
if (counters < 0)
format = FMT_C_COUNTS;
else if (counters == 0)
format = FMT_NOCOUNTS;
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- const char *chain_table =
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c)
+ return 0;
- if (strcmp(table, chain_table) != 0)
- goto next;
- if (chain && strcmp(chain, chain_name) != 0)
- goto next;
+ return __nft_rule_list(h, c, rulenum, format, list_save);
+ }
- ret = __nft_rule_list(h, chain_name, table, rulenum,
- format, list_save);
+ /* Now dump out rules in this table */
+ iter = nftnl_chain_list_iter_create(list);
+ if (iter == NULL)
+ return 0;
- /* we printed the chain we wanted, stop processing. */
- if (chain)
- break;
-next:
+ c = nftnl_chain_list_iter_next(iter);
+ while (c != NULL) {
+ ret = __nft_rule_list(h, c, rulenum, format, list_save);
c = nftnl_chain_list_iter_next(iter);
}
-
nftnl_chain_list_iter_destroy(iter);
-err:
return ret;
}
@@ -2516,17 +2660,17 @@ 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_list *list;
+ struct nftnl_chain *c;
struct nftnl_rule *r;
int ret = 0;
nft_fn = nft_rule_delete;
- list = nft_rule_list_get(h);
- if (list == NULL)
+ c = nft_chain_find(h, table, chain);
+ if (!c)
return 0;
- r = nft_rule_find(h, list, chain, table, NULL, rulenum);
+ r = nft_rule_find(h, c, NULL, rulenum);
if (r == NULL) {
errno = ENOENT;
ret = 1;
@@ -2537,9 +2681,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
cs.counters.pcnt = cs.counters.bcnt = 0;
- ret = nft_rule_append(h, chain, table, &cs,
- nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
- false);
+ ret = nft_rule_append(h, chain, table, &cs, r, false);
error:
return ret;
@@ -2589,8 +2731,8 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
break;
case NFT_COMPAT_CHAIN_ZERO:
case NFT_COMPAT_CHAIN_USER_ADD:
- break;
case NFT_COMPAT_CHAIN_ADD:
+ break;
case NFT_COMPAT_CHAIN_USER_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
@@ -2611,6 +2753,71 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
free(o);
}
+static void nft_refresh_transaction(struct nft_handle *h)
+{
+ const char *tablename, *chainname;
+ const struct nftnl_chain *c;
+ struct obj_update *n, *tmp;
+ bool exists;
+
+ h->error.lineno = 0;
+
+ list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
+ if (n->implicit) {
+ batch_obj_del(h, n);
+ continue;
+ }
+
+ switch (n->type) {
+ case NFT_COMPAT_TABLE_FLUSH:
+ tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
+ if (!tablename)
+ continue;
+ exists = nft_table_find(h, tablename);
+ if (exists)
+ n->skip = 0;
+ else
+ n->skip = 1;
+ break;
+ case NFT_COMPAT_CHAIN_USER_ADD:
+ tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE);
+ if (!tablename)
+ continue;
+
+ chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME);
+ if (!chainname)
+ continue;
+
+ if (!h->noflush)
+ break;
+
+ c = nft_chain_find(h, tablename, chainname);
+ if (c) {
+ /* -restore -n flushes existing rules from redefined user-chain */
+ __nft_rule_flush(h, tablename,
+ chainname, false, true);
+ n->skip = 1;
+ } else if (!c) {
+ n->skip = 0;
+ }
+ break;
+ case NFT_COMPAT_TABLE_ADD:
+ case NFT_COMPAT_CHAIN_ADD:
+ case NFT_COMPAT_CHAIN_ZERO:
+ case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_USER_FLUSH:
+ case NFT_COMPAT_CHAIN_UPDATE:
+ case NFT_COMPAT_CHAIN_RENAME:
+ case NFT_COMPAT_RULE_APPEND:
+ case NFT_COMPAT_RULE_INSERT:
+ case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_DELETE:
+ case NFT_COMPAT_RULE_FLUSH:
+ break;
+ }
+ }
+}
+
static int nft_action(struct nft_handle *h, int action)
{
struct obj_update *n, *tmp;
@@ -2618,14 +2825,21 @@ static int nft_action(struct nft_handle *h, int action)
unsigned int buflen, i, len;
bool show_errors = true;
char errmsg[1024];
- uint32_t seq = 1;
+ uint32_t seq;
int ret = 0;
+retry:
+ seq = 1;
h->batch = mnl_batch_init();
- mnl_batch_begin(h->batch, seq++);
+ mnl_batch_begin(h->batch, h->nft_genid, seq++);
+ h->nft_genid++;
list_for_each_entry(n, &h->obj_list, head) {
+
+ if (n->skip)
+ continue;
+
n->seq = seq++;
switch (n->type) {
case NFT_COMPAT_TABLE_ADD:
@@ -2702,7 +2916,20 @@ static int nft_action(struct nft_handle *h, int action)
break;
}
+ errno = 0;
ret = mnl_batch_talk(h->nl, h->batch, &h->err_list);
+ if (ret && errno == ERESTART) {
+ nft_rebuild_cache(h);
+
+ nft_refresh_transaction(h);
+
+ i=0;
+ list_for_each_entry_safe(err, ne, &h->err_list, head)
+ mnl_err_list_free(err);
+
+ mnl_batch_reset(h->batch);
+ goto retry;
+ }
i = 0;
buflen = sizeof(errmsg);
@@ -2726,6 +2953,7 @@ static int nft_action(struct nft_handle *h, int action)
batch_obj_del(h, n);
}
+ nft_release_cache(h);
mnl_batch_reset(h->batch);
if (i)
@@ -2734,8 +2962,111 @@ static int nft_action(struct nft_handle *h, int action)
return ret == 0 ? 1 : 0;
}
+static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
+{
+ uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
+ struct iptables_command_state cs = {
+ .eb.bitmask = EBT_NOPROTO,
+ };
+ struct nftnl_udata_buf *udata;
+ struct nft_handle *h = data;
+ struct nftnl_rule *r;
+ const char *pname;
+
+ if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
+ return 0; /* ignore base chains */
+
+ if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
+ return 0;
+
+ nftnl_chain_unset(c, NFTNL_CHAIN_POLICY);
+
+ switch (policy) {
+ case NFT_RETURN:
+ return 0; /* return policy is default for nft chains */
+ case NF_ACCEPT:
+ pname = "ACCEPT";
+ break;
+ case NF_DROP:
+ pname = "DROP";
+ break;
+ default:
+ return -1;
+ }
+
+ command_jump(&cs, pname);
+
+ r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
+ nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
+ if (!r)
+ return -1;
+
+ udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udata)
+ return -1;
+
+ if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
+ return -1;
+
+ 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;
+ }
+
+ return 0;
+}
+
+int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy)
+{
+ struct nftnl_chain *c = nft_chain_find(h, table, chain);
+ int pval;
+
+ if (!c)
+ return 0;
+
+ if (!strcmp(policy, "DROP"))
+ pval = NF_DROP;
+ else if (!strcmp(policy, "ACCEPT"))
+ pval = NF_ACCEPT;
+ else if (!strcmp(policy, "RETURN"))
+ pval = NFT_RETURN;
+ else
+ return 0;
+
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
+ return 1;
+}
+
+static void nft_bridge_commit_prepare(struct nft_handle *h)
+{
+ const struct builtin_table *t;
+ struct nftnl_chain_list *list;
+ int i;
+
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ t = &h->tables[i];
+
+ if (!t->name)
+ continue;
+
+ list = h->cache->table[t->type].chains;
+ if (!list)
+ continue;
+
+ nftnl_chain_list_foreach(list, ebt_add_policy_rule, h);
+ }
+}
+
int nft_commit(struct nft_handle *h)
{
+ if (h->family == NFPROTO_BRIDGE)
+ nft_bridge_commit_prepare(h);
return nft_action(h, NFT_COMPAT_COMMIT);
}
@@ -2744,6 +3075,27 @@ int nft_abort(struct nft_handle *h)
return nft_action(h, NFT_COMPAT_ABORT);
}
+int nft_abort_policy_rule(struct nft_handle *h, const char *table)
+{
+ struct obj_update *n, *tmp;
+
+ 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;
+
+ if (strcmp(table,
+ nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
+ continue;
+
+ if (!nft_rule_is_policy_rule(n->rule))
+ continue;
+
+ batch_obj_del(h, n);
+ }
+ return 0;
+}
+
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
{
struct mnl_socket *nl;
@@ -2830,10 +3182,11 @@ const char *nft_strerror(int err)
{ nft_chain_user_del, EMLINK,
"Can't delete chain with references left" },
{ nft_chain_user_add, EEXIST, "Chain already exists" },
- { nft_rule_insert, ENOENT, "Index of insertion too big" },
+ { nft_chain_user_rename, EEXIST, "File exists" },
+ { nft_rule_insert, E2BIG, "Index of insertion too big" },
{ nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
- { nft_rule_replace, ENOENT, "Index of replacement too big" },
- { nft_rule_delete_num, ENOENT, "Index of deletion too big" },
+ { nft_rule_replace, E2BIG, "Index of replacement too big" },
+ { nft_rule_delete_num, E2BIG, "Index of deletion too big" },
/* { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
{ TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
/* ENOENT for DELETE probably means no matching rule */
@@ -2992,41 +3345,41 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename,
return h->config_done;
}
-static void nft_chain_zero_rule_counters(struct nft_handle *h,
- struct nftnl_chain *c)
+struct chain_zero_data {
+ struct nft_handle *handle;
+ bool verbose;
+};
+
+static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
{
- struct nftnl_rule_list_iter *iter;
- struct nftnl_rule_list *list;
- const char *table_name;
- const char *chain_name;
+ struct chain_zero_data *d = data;
+ struct nft_handle *h = d->handle;
+ struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
- list = nft_rule_list_get(h);
- if (list == NULL)
- return;
- iter = nftnl_rule_list_iter_create(list);
- if (iter == NULL)
- return;
+ if (d->verbose)
+ fprintf(stdout, "Zeroing chain `%s'\n",
+ nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
- table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
+ /* zero base chain counters. */
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
+ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
+ if (batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
+ return -1;
+ }
+
+ iter = nftnl_rule_iter_create(c);
+ if (iter == NULL)
+ return -1;
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
while (r != NULL) {
struct nftnl_expr_iter *ei;
- const char *table_chain;
- const char *rule_chain;
struct nftnl_expr *e;
bool zero_needed;
- table_chain = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
- if (strcmp(table_chain, table_name))
- goto next;
-
- rule_chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
- if (strcmp(rule_chain, chain_name))
- goto next;
-
ei = nftnl_expr_iter_create(r);
if (!ei)
break;
@@ -3055,67 +3408,45 @@ static void nft_chain_zero_rule_counters(struct nft_handle *h,
* rule based on its handle only.
*/
nftnl_rule_unset(r, NFTNL_RULE_POSITION);
- batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r);
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
+ nftnl_rule_iter_destroy(iter);
+ return -1;
+ }
}
-next:
- r = nftnl_rule_list_iter_next(iter);
+ r = nftnl_rule_iter_next(iter);
}
- nftnl_rule_list_iter_destroy(iter);
+ nftnl_rule_iter_destroy(iter);
+ return 0;
}
int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
+ struct chain_zero_data d = {
+ .handle = h,
+ .verbose = verbose,
+ };
struct nftnl_chain *c;
int ret = 0;
- list = nft_chain_list_get(h);
+ list = nft_chain_list_get(h, table);
if (list == NULL)
goto err;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- goto err;
-
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- const char *chain_name =
- nftnl_chain_get(c, NFTNL_CHAIN_NAME);
- const char *chain_table =
- nftnl_chain_get(c, NFTNL_CHAIN_TABLE);
-
- if (strcmp(table, chain_table) != 0)
- goto next;
-
- if (chain != NULL && strcmp(chain, chain_name) != 0)
- goto next;
-
- if (verbose)
- fprintf(stdout, "Zeroing chain `%s'\n", chain_name);
-
- if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
- /* zero base chain counters. */
- nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
- nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ if (!c) {
+ errno = ENOENT;
+ return 0;
}
- nft_chain_zero_rule_counters(h, c);
-
- nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
-
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c);
-
- if (chain != NULL)
- break;
-next:
- c = nftnl_chain_list_iter_next(iter);
+ ret = __nft_chain_zero_counters(c, &d);
+ goto err;
}
- nftnl_chain_list_iter_destroy(iter);
-
+ ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -3143,7 +3474,7 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
};
-static int nft_is_expr_compatible(const struct nftnl_expr *expr)
+static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
{
const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
int i;
@@ -3158,143 +3489,60 @@ static int nft_is_expr_compatible(const struct nftnl_expr *expr)
nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
return 0;
- return 1;
+ return -1;
}
-static bool nft_is_rule_compatible(struct nftnl_rule *rule)
+static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
{
- struct nftnl_expr_iter *iter;
- struct nftnl_expr *expr;
- bool compatible = false;
-
- iter = nftnl_expr_iter_create(rule);
- if (iter == NULL)
- return false;
-
- expr = nftnl_expr_iter_next(iter);
- while (expr != NULL) {
- if (nft_is_expr_compatible(expr) == 0) {
- expr = nftnl_expr_iter_next(iter);
- continue;
- }
-
- compatible = true;
- break;
- }
-
- nftnl_expr_iter_destroy(iter);
- return compatible;
+ return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
}
-static int nft_is_chain_compatible(const struct nft_handle *h,
- const struct nftnl_chain *chain)
+static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
{
- const char *table, *name, *type, *cur_table;
- struct builtin_chain *chains;
- int i, j, prio;
+ const struct builtin_table *table;
+ const struct builtin_chain *chain;
+ const char *tname, *cname, *type;
+ struct nft_handle *h = data;
enum nf_inet_hooks hook;
+ int prio;
- table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE);
- name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME);
- type = nftnl_chain_get(chain, NFTNL_CHAIN_TYPE);
- prio = nftnl_chain_get_u32(chain, NFTNL_CHAIN_PRIO);
- hook = nftnl_chain_get_u32(chain, NFTNL_CHAIN_HOOKNUM);
-
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- cur_table = h->tables[i].name;
- chains = h->tables[i].chains;
-
- if (!cur_table || strcmp(table, cur_table) != 0)
- continue;
-
- for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) {
- if (strcmp(name, chains[j].name) != 0)
- continue;
-
- if (strcmp(type, chains[j].type) == 0 &&
- prio == chains[j].prio &&
- hook == chains[j].hook)
- return 0;
- break;
- }
- }
-
- return 1;
-}
+ if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
+ return -1;
-static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename)
-{
- struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain *chain;
- int ret = 0;
+ if (!nft_chain_builtin(c))
+ return 0;
- list = nft_chain_list_get(h);
- if (list == NULL)
+ tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
+ table = nft_table_builtin_find(h, tname);
+ if (!table)
return -1;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
+ cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ chain = nft_chain_builtin_find(table, cname);
+ if (!chain)
return -1;
- chain = nftnl_chain_list_iter_next(iter);
- while (chain != NULL) {
- const char *chain_table;
-
- chain_table = nftnl_chain_get_str(chain, NFTNL_CHAIN_TABLE);
-
- if (strcmp(chain_table, tablename) ||
- !nft_chain_builtin(chain))
- goto next;
-
- ret = nft_is_chain_compatible(h, chain);
- if (ret != 0)
- break;
-next:
- chain = nftnl_chain_list_iter_next(iter);
- }
-
- nftnl_chain_list_iter_destroy(iter);
+ type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE);
+ prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO);
+ hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
+ if (strcmp(type, chain->type) ||
+ prio != chain->prio ||
+ hook != chain->hook)
+ return -1;
- return ret;
+ return 0;
}
bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
{
- struct nftnl_rule_list *list;
- struct nftnl_rule_list_iter *iter;
- struct nftnl_rule *rule;
- int ret = 0;
+ struct nftnl_chain_list *clist;
- if (!nft_table_builtin_find(h, tablename))
+ clist = nft_chain_list_get(h, tablename);
+ if (clist == NULL)
return false;
- ret = nft_are_chains_compatible(h, tablename);
- if (ret != 0)
+ if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
return false;
- list = nft_rule_list_get(h);
- if (list == NULL)
- return true;
-
- iter = nftnl_rule_list_iter_create(list);
- if (iter == NULL)
- return true;
-
- rule = nftnl_rule_list_iter_next(iter);
- while (rule != NULL) {
- const char *table = nftnl_rule_get_str(rule, NFTNL_RULE_TABLE);
-
- if (strcmp(table, tablename))
- goto next_rule;
-
- ret = nft_is_rule_compatible(rule);
- if (ret != 0)
- break;
-next_rule:
- rule = nftnl_rule_list_iter_next(iter);
- }
-
- nftnl_rule_list_iter_destroy(iter);
- return ret == 0;
+ return true;
}
diff --git a/iptables/nft.h b/iptables/nft.h
index 9b4ba5f9..43eb8a39 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -23,8 +23,16 @@ struct builtin_chain {
struct builtin_table {
const char *name;
+ enum nft_table_type type;
struct builtin_chain chains[NF_INET_NUMHOOKS];
- bool initialized;
+};
+
+struct nft_cache {
+ struct nftnl_table_list *tables;
+ struct {
+ struct nftnl_chain_list *chains;
+ bool initialized;
+ } table[NFT_TABLE_MAX];
};
struct nft_handle {
@@ -32,15 +40,20 @@ struct nft_handle {
struct mnl_socket *nl;
uint32_t portid;
uint32_t seq;
+ uint32_t nft_genid;
+ uint32_t rule_id;
struct list_head obj_list;
int obj_list_num;
struct nftnl_batch *batch;
struct list_head err_list;
struct nft_family_ops *ops;
- struct builtin_table *tables;
- struct nftnl_chain_list *chain_cache;
- struct nftnl_rule_list *rule_cache;
+ const struct builtin_table *tables;
+ unsigned int cache_index;
+ struct nft_cache __cache[2];
+ struct nft_cache *cache;
+ bool have_cache;
bool restore;
+ bool noflush;
int8_t config_done;
/* meta data, for error reporting */
@@ -49,15 +62,16 @@ struct nft_handle {
} error;
};
-extern struct builtin_table xtables_ipv4[NFT_TABLE_MAX];
-extern struct builtin_table xtables_arp[NFT_TABLE_MAX];
-extern struct builtin_table xtables_bridge[NFT_TABLE_MAX];
+extern const struct builtin_table xtables_ipv4[NFT_TABLE_MAX];
+extern const struct builtin_table xtables_arp[NFT_TABLE_MAX];
+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, struct builtin_table *t);
+int nft_init(struct nft_handle *h, const struct builtin_table *t);
void nft_fini(struct nft_handle *h);
+void nft_build_cache(struct nft_handle *h);
/*
* Operations with tables.
@@ -70,7 +84,7 @@ bool nft_table_find(struct nft_handle *h, const char *tablename);
int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list);
int nft_table_flush(struct nft_handle *h, const char *table);
void nft_table_new(struct nft_handle *h, const char *table);
-struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
+const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
/*
* Operations with chains.
@@ -78,16 +92,15 @@ struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *t
struct nftnl_chain;
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h);
-struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *table, const char *chain);
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table);
+struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
+ const char *table);
+int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list);
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
-int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list,
- const char *chain, const char *table);
+int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *table, const char *newname);
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose);
-struct builtin_chain *nft_chain_builtin_find(struct builtin_table *t, const char *chain);
+const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t, const char *chain);
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
/*
@@ -95,7 +108,7 @@ bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain
*/
struct nftnl_rule;
-int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, uint64_t handle, bool verbose);
+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);
@@ -116,7 +129,6 @@ int add_match(struct nftnl_rule *r, struct xt_entry_match *m);
int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
-int add_comment(struct nftnl_rule *r, const char *comment);
char *get_comment(const void *data, uint32_t data_len);
enum nft_rule_print {
@@ -134,6 +146,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
*/
int nft_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.
@@ -200,4 +213,7 @@ void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
bool nft_is_table_compatible(struct nft_handle *h, const char *name);
+int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy);
+
#endif
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index b6eb01c6..7bef09f7 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -3,10 +3,6 @@
#configuration
TESTDIR="./$(dirname $0)/"
RETURNCODE_SEPARATOR="_"
-XTABLES_NFT_MULTI="$(dirname $0)/../../xtables-nft-multi"
-XTABLES_LEGACY_MULTI="$(dirname $0)/../../xtables-legacy-multi"
-
-export XTABLES_LIBDIR=${TESTDIR}/../../../extensions
msg_error() {
echo "E: $1 ..." >&2
@@ -29,20 +25,40 @@ if [ ! -d "$TESTDIR" ] ; then
msg_error "missing testdir $TESTDIR"
fi
-if [ "$1" == "-v" ] ; then
- VERBOSE=y
- shift
-fi
-
-for arg in "$@"; do
- if grep ^.*${RETURNCODE_SEPARATOR}[0-9]\\+$ <<< $arg >/dev/null ; then
- SINGLE+=" $arg"
- VERBOSE=y
- else
- msg_error "unknown parameter '$arg'"
- fi
+# support matching repeated pattern in SINGLE check below
+shopt -s extglob
+
+while [ -n "$1" ]; do
+ case "$1" in
+ -v|--verbose)
+ VERBOSE=y
+ shift
+ ;;
+ -H|--host)
+ HOST=y
+ shift
+ ;;
+ *${RETURNCODE_SEPARATOR}+([0-9]))
+ SINGLE+=" $1"
+ VERBOSE=y
+ shift
+ ;;
+ *)
+ msg_error "unknown parameter '$1'"
+ ;;
+ esac
done
+if [ "$HOST" != "y" ]; then
+ XTABLES_NFT_MULTI="$(dirname $0)/../../xtables-nft-multi"
+ XTABLES_LEGACY_MULTI="$(dirname $0)/../../xtables-legacy-multi"
+
+ export XTABLES_LIBDIR=${TESTDIR}/../../../extensions
+else
+ XTABLES_NFT_MULTI="xtables-nft-multi"
+ XTABLES_LEGACY_MULTI="xtables-legacy-multi"
+fi
+
find_tests() {
if [ ! -z "$SINGLE" ] ; then
echo $SINGLE
diff --git a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
index 73b3b0cf..e10f61cc 100755
--- a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
+++ b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
@@ -35,22 +35,22 @@ DUMP='*filter
:INPUT ACCEPT
:OUTPUT DROP
:foo -
--A INPUT -s 10.0.0.0/8 --h-length 6 --h-type 1 -j ACCEPT
--A INPUT -d 192.168.123.1 --h-length 6 --h-type 1 -j ACCEPT
--A INPUT --src-mac fe:ed:ba:be:00:01 --h-length 6 --h-type 1 -j ACCEPT
--A INPUT --dst-mac fe:ed:ba:be:00:01 --h-length 6 --h-type 1 -j ACCEPT
--A INPUT --h-length 6 --h-type 1 -j foo
--A INPUT --h-length 6 --h-type 1
--A OUTPUT -o lo --h-length 6 --h-type 1 -j ACCEPT
--A OUTPUT -o eth134 --h-length 6 --h-type 1 -j mangle --mangle-ip-s 10.0.0.1
--A OUTPUT -o eth432 --h-length 6 --h-type 1 -j CLASSIFY --set-class feed:babe
--A OUTPUT -o eth432 --h-length 6 --opcode 1 --h-type 1 -j CLASSIFY --set-class feed:babe
--A foo -i lo --h-length 6 --h-type 1 -j ACCEPT
--A foo --h-length 6 --h-type 1 -j ACCEPT
--A foo --h-length 6 --h-type 1 -j MARK --set-xmark 0x3039/0xffffffff
--A foo --h-length 6 --opcode 1 --h-type 1 -j ACCEPT
--A foo --h-length 6 --h-type 1 --proto-type 0x800 -j ACCEPT
--A foo -i lo --h-length 6 --opcode 1 --h-type 1 --proto-type 0x800 -j ACCEPT
+-A INPUT -j ACCEPT -s 10.0.0.0/8
+-A INPUT -j ACCEPT -d 192.168.123.1
+-A INPUT -j ACCEPT --src-mac fe:ed:ba:be:00:01
+-A INPUT -j ACCEPT --dst-mac fe:ed:ba:be:00:01
+-A INPUT -j foo
+-A INPUT
+-A OUTPUT -j ACCEPT -o lo
+-A OUTPUT -j mangle -o eth134 --mangle-ip-s 10.0.0.1
+-A OUTPUT -j CLASSIFY -o eth432 --set-class feed:babe
+-A OUTPUT -j CLASSIFY -o eth432 --opcode 1 --set-class feed:babe
+-A foo -j ACCEPT -i lo
+-A foo -j ACCEPT
+-A foo -j MARK --set-mark 12345
+-A foo -j ACCEPT --opcode 1
+-A foo -j ACCEPT --proto-type 0x800
+-A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800
'
diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save)
diff --git a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
index ee17da00..b2ed95e8 100755
--- a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
@@ -11,7 +11,7 @@ set -e
DUMP='*filter
:OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
--A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-d 10.0.0.2
+-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
'
# note how mangle-ip-s is unset in second rule
@@ -19,8 +19,8 @@ DUMP='*filter
EXPECT='*filter
:INPUT ACCEPT
:OUTPUT ACCEPT
--A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-s 10.0.0.1
--A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-d 10.0.0.2
+-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
+-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
'
$XT_MULTI arptables -F
diff --git a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
new file mode 100755
index 00000000..3a9807a1
--- /dev/null
+++ b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+set -e
+set -x
+
+# there is no legacy backend to test
+[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+$XT_MULTI arptables -N foo
+
+# check verbose output matches expectations
+
+RULE1='-i eth23 -j ACCEPT'
+VOUT1='-j ACCEPT -i eth23 -o *'
+
+RULE2='-i eth23'
+VOUT2='-i eth23 -o *'
+
+RULE3='-i eth23 -j MARK --set-mark 42'
+VOUT3='-j MARK -i eth23 -o * --set-mark 42'
+
+RULE4='-o eth23 -j CLASSIFY --set-class 23:42'
+VOUT4='-j CLASSIFY -i * -o eth23 --set-class 23:42'
+
+RULE5='-o eth23 -j foo'
+VOUT5='-j foo -i * -o eth23'
+
+RULE6='-o eth23 -j mangle --mangle-ip-s 10.0.0.1'
+VOUT6='-j mangle -i * -o eth23 --mangle-ip-s 10.0.0.1'
+
+diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI arptables -v -A INPUT $RULE1)
+diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI arptables -v -A INPUT $RULE2)
+diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI arptables -v -A INPUT $RULE3)
+diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI arptables -v -A OUTPUT $RULE4)
+diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI arptables -v -A OUTPUT $RULE5)
+diff -u -Z <(echo -e "$VOUT6") <($XT_MULTI arptables -v -A foo $RULE6)
+
+EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
+-j ACCEPT -i eth23 -o * , pcnt=0 -- bcnt=0
+-i eth23 -o * , pcnt=0 -- bcnt=0
+-j MARK -i eth23 -o * --set-mark 42 , pcnt=0 -- bcnt=0
+
+Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
+-j CLASSIFY -i * -o eth23 --set-class 23:42 , pcnt=0 -- bcnt=0
+-j foo -i * -o eth23 , pcnt=0 -- bcnt=0
+
+Chain foo (1 references)
+-j mangle -i * -o eth23 --mangle-ip-s 10.0.0.1 , pcnt=0 -- bcnt=0'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables -v -n -L)
+
+EXPECT='*filter
+:INPUT ACCEPT
+:OUTPUT ACCEPT
+:foo -
+-A INPUT -j ACCEPT -i eth23
+-A INPUT -i eth23
+-A INPUT -j MARK -i eth23 --set-mark 42
+-A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42
+-A OUTPUT -j foo -o eth23
+-A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1
+'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save)
diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
index b23c1ee1..080ba49a 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -50,6 +50,9 @@ $XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT
$XT_MULTI ebtables -A FORWARD -j foo
+$XT_MULTI ebtables -N bar
+$XT_MULTI ebtables -P bar RETURN
+
$XT_MULTI ebtables -t nat -A PREROUTING --redirect-target ACCEPT
#$XT_MULTI ebtables -t nat -A PREROUTING --to-src fe:ed:ba:be:00:01
@@ -59,6 +62,8 @@ $XT_MULTI ebtables -t nat -P OUTPUT DROP
$XT_MULTI ebtables -t nat -A POSTROUTING -j ACCEPT
#$XT_MULTI ebtables -t nat -A POSTROUTING --to-dst fe:ed:ba:be:00:01 --dnat-target ACCEPT
+$XT_MULTI ebtables -t nat -N nat_foo -P DROP
+
# compare against stored ebtables dump
DUMP='*filter
@@ -66,6 +71,7 @@ DUMP='*filter
:FORWARD DROP
:OUTPUT ACCEPT
:foo ACCEPT
+:bar RETURN
-A INPUT -p IPv4 -i lo -j ACCEPT
-A FORWARD -j foo
-A OUTPUT -s Broadcast -j DROP
@@ -98,6 +104,7 @@ DUMP='*filter
:PREROUTING ACCEPT
:OUTPUT DROP
:POSTROUTING ACCEPT
+:nat_foo DROP
-A PREROUTING -j redirect
-A OUTPUT -j ACCEPT
-A POSTROUTING -j ACCEPT
diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
new file mode 100755
index 00000000..51f2422e
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
@@ -0,0 +1,117 @@
+#!/bin/bash
+
+# Make sure iptables-restore does the right thing
+# when encountering INSERT rules with index.
+
+set -e
+
+# show rules, drop uninteresting policy settings
+ipt_show() {
+ $XT_MULTI iptables -S | grep -v '^-P'
+}
+
+# basic issue reproducer
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT
+-I FORWARD 1 -m comment --comment "rule 1" -j ACCEPT
+-I FORWARD 2 -m comment --comment "rule 2" -j ACCEPT
+-I FORWARD 3 -m comment --comment "rule 3" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+# insert rules into existing ruleset
+
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter
+-I FORWARD 1 -m comment --comment "rule 0.5" -j ACCEPT
+-I FORWARD 3 -m comment --comment "rule 1.5" -j ACCEPT
+-I FORWARD 5 -m comment --comment "rule 2.5" -j ACCEPT
+-I FORWARD 7 -m comment --comment "rule 3.5" -j ACCEPT
+-I FORWARD 9 -m comment --comment "appended rule 2" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "rule 0.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "rule 1.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 2.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3.5" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+# insert rules in between added ones
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment "appended rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT
+-I FORWARD 1 -m comment --comment "rule 1" -j ACCEPT
+-I FORWARD 3 -m comment --comment "rule 2" -j ACCEPT
+-I FORWARD 5 -m comment --comment "rule 3" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+# test rule deletion in dump files
+
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter
+-D FORWARD -m comment --comment "appended rule 1" -j ACCEPT
+-D FORWARD 3
+-I FORWARD 3 -m comment --comment "manually replaced rule 2" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "manually replaced rule 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+# test rule replacement in dump files
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "rule to be replaced" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
+COMMIT
+EOF
+
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter
+-R FORWARD 2 -m comment --comment "replacement" -j ACCEPT
+-I FORWARD 2 -m comment --comment "insert referencing replaced rule" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "insert referencing replaced rule" -j ACCEPT
+-A FORWARD -m comment --comment replacement -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0 b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
new file mode 100755
index 00000000..a92d18dc
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
@@ -0,0 +1,118 @@
+#!/bin/bash
+
+have_nft=false
+nft -v > /dev/null && have_nft=true
+
+dumpfile=""
+tmpfile=""
+
+set -e
+
+clean()
+{
+ $XT_MULTI iptables -t filter -F
+ $XT_MULTI iptables -t filter -X
+ $have_nft && nft flush ruleset
+}
+
+clean_tempfile()
+{
+ [ -n "${tmpfile}" ] && rm -f "${tmpfile}"
+ [ -n "${dumpfile}" ] && rm -f "${dumpfile}"
+ clean
+}
+
+trap clean_tempfile EXIT
+
+ENTRY_NUM=$((RANDOM%100))
+UCHAIN_NUM=$((RANDOM%10))
+
+get_target()
+{
+ if [ $UCHAIN_NUM -eq 0 ]; then
+ echo -n "ACCEPT"
+ return
+ fi
+
+
+ x=$((RANDOM%2))
+ if [ $x -eq 0 ];then
+ echo -n "ACCEPT"
+ else
+ printf -- "UC-%x" $((RANDOM%UCHAIN_NUM))
+ fi
+}
+
+make_dummy_rules()
+{
+
+ echo "*filter"
+ echo ":INPUT ACCEPT [0:0]"
+ echo ":FORWARD ACCEPT [0:0]"
+ echo ":OUTPUT ACCEPT [0:0]"
+
+ if [ $UCHAIN_NUM -gt 0 ]; then
+ for i in $(seq 0 $UCHAIN_NUM); do
+ printf -- ":UC-%x - [0:0]\n" $i
+ done
+ fi
+
+ for proto in tcp udp sctp; do
+ for i in $(seq 0 $ENTRY_NUM); do
+ t=$(get_target)
+ printf -- "-A INPUT -i lo -p $proto --dport %d -j %s\n" $((61000-i)) $t
+ t=$(get_target)
+ printf -- "-A FORWARD -i lo -o lo -p $proto --dport %d -j %s\n" $((61000-i)) $t
+ t=$(get_target)
+ printf -- "-A OUTPUT -o lo -p $proto --dport %d -j %s\n" $((61000-i)) $t
+ [ $UCHAIN_NUM -gt 0 ] && printf -- "-A UC-%x -j ACCEPT\n" $((RANDOM%UCHAIN_NUM))
+ done
+ done
+ echo COMMIT
+}
+
+tmpfile=$(mktemp) || exit 1
+dumpfile=$(mktemp) || exit 1
+
+make_dummy_rules > $dumpfile
+$XT_MULTI iptables-restore -w < $dumpfile
+LINES1=$(wc -l < $dumpfile)
+$XT_MULTI iptables-save | grep -v '^#' > $dumpfile
+LINES2=$(wc -l < $dumpfile)
+
+if [ $LINES1 -ne $LINES2 ]; then
+ echo "Original dump has $LINES1, not $LINES2" 1>&2
+ exit 111
+fi
+
+case "$XT_MULTI" in
+*/xtables-nft-multi)
+ attempts=$((RANDOM%200))
+ attempts=$((attempts+1))
+ ;;
+*)
+ attempts=1
+ ;;
+esac
+
+while [ $attempts -gt 0 ]; do
+ attempts=$((attempts-1))
+
+ clean
+
+ for i in $(seq 1 10); do
+ $XT_MULTI iptables-restore -w 15 < $dumpfile &
+ done
+
+ for i in $(seq 1 10); do
+ # causes exit in case ipt-restore failed (runs with set -e)
+ wait %$i
+ done
+
+ $XT_MULTI iptables-save | grep -v '^#' > $tmpfile
+
+ clean
+ cmp $tmpfile $dumpfile
+done
+
+exit 0
diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
index 2e805953..b1ef91f6 100755
--- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
@@ -29,23 +29,28 @@ Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -n -L)
+[[ -z $($XT_MULTI iptables -v -N foobar) ]] || exit 1
+
diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI iptables -v -D FORWARD $RULE1)
diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI iptables -v -D FORWARD $RULE2)
EXPECT="Flushing chain \`INPUT'
Flushing chain \`FORWARD'
-Flushing chain \`OUTPUT'"
+Flushing chain \`OUTPUT'
+Flushing chain \`foobar'"
diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -F)
EXPECT="Zeroing chain \`INPUT'
Zeroing chain \`FORWARD'
-Zeroing chain \`OUTPUT'"
+Zeroing chain \`OUTPUT'
+Zeroing chain \`foobar'"
diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -Z)
diff -u <(echo "Flushing chain \`OUTPUT'") <($XT_MULTI iptables -v -F OUTPUT)
diff -u <(echo "Zeroing chain \`OUTPUT'") <($XT_MULTI iptables -v -Z OUTPUT)
+diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar)
+diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar)
-$XT_MULTI iptables -N foo
-diff -u <(echo "Deleting chain \`foo'") <($XT_MULTI iptables -v -X foo)
+diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar)
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index 5b6e1f6f..ce02e0bc 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -1,42 +1,81 @@
-#!/bin/sh
+#!/bin/bash
# make sure error return codes are as expected useful cases
# (e.g. commands to check ruleset state)
global_rc=0
-cmd() { # (rc, cmd, [args ...])
+cmd() { # (rc, msg, cmd, [args ...])
rc_exp=$1; shift
- $XT_MULTI "$@"
+ msg_exp=""
+ [ $rc_exp != 0 ] && {
+ msg_exp="$1"; shift
+ }
+
+ msg="$($XT_MULTI "$@" 2>&1 >/dev/null)"
rc=$?
[ $rc -eq $rc_exp ] || {
- echo "---> expected $rc_exp, got $rc for command '$@'"
+ echo "---> expected return code $rc_exp, got $rc for command '$@'"
+ global_rc=1
+ }
+
+ [ -n "$msg_exp" ] || return
+ grep -q "$msg_exp" <<< $msg || {
+ echo "---> expected error message '$msg_exp', got '$msg' for command '$@'"
global_rc=1
}
}
+EEXIST_F="File exists."
+EEXIST="Chain already exists."
+ENOENT="No chain/target/match by that name."
+E2BIG_I="Index of insertion too big."
+E2BIG_D="Index of deletion too big."
+E2BIG_R="Index of replacement too big."
+EBADRULE="Bad rule (does a matching rule exist in that chain?)."
+ENOTGT="Couldn't load target \`foobar':No such file or directory"
+ENOMTH="Couldn't load match \`foobar':No such file or directory"
+ENOTBL="can't initialize iptables table \`foobar': Table does not exist"
+
# test chain creation
cmd 0 iptables -N foo
-cmd 1 iptables -N foo
+cmd 1 "$EEXIST" iptables -N foo
# iptables-nft allows this - bug or feature?
#cmd 2 iptables -N "invalid name"
+# test chain flushing/zeroing
+cmd 0 iptables -F foo
+cmd 0 iptables -Z foo
+cmd 1 "$ENOENT" iptables -F bar
+cmd 1 "$ENOENT" iptables -Z bar
+
# test chain rename
cmd 0 iptables -E foo bar
-cmd 1 iptables -E foo bar
+cmd 1 "$EEXIST_F" iptables -E foo bar
# test rule adding
cmd 0 iptables -A INPUT -j ACCEPT
-cmd 1 iptables -A noexist -j ACCEPT
+cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
+
+# test rulenum commands
+cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT
+cmd 1 "$E2BIG_D" iptables -D INPUT 23
+cmd 1 "$E2BIG_R" iptables -R INPUT 23 -j ACCEPT
+cmd 1 "$ENOENT" iptables -I nonexist 23 -j ACCEPT
+cmd 1 "$ENOENT" iptables -D nonexist 23
+cmd 1 "$ENOENT" iptables -R nonexist 23 -j ACCEPT
# test rule checking
cmd 0 iptables -C INPUT -j ACCEPT
-cmd 1 iptables -C FORWARD -j ACCEPT
-cmd 1 iptables -C nonexist -j ACCEPT
-cmd 2 iptables -C INPUT -j foobar
-cmd 2 iptables -C INPUT -m foobar -j ACCEPT
-cmd 3 iptables -t foobar -C INPUT -j ACCEPT
+cmd 1 "$EBADRULE" iptables -C FORWARD -j ACCEPT
+cmd 1 "$BADRULE" iptables -C nonexist -j ACCEPT
+cmd 2 "$ENOMTH" iptables -C INPUT -m foobar -j ACCEPT
+# messages of those don't match, but iptables-nft ones are actually nicer.
+#cmd 2 "$ENOTGT" iptables -C INPUT -j foobar
+#cmd 3 "$ENOTBL" iptables -t foobar -C INPUT -j ACCEPT
+cmd 2 "" iptables -C INPUT -j foobar
+cmd 3 "" iptables -t foobar -C INPUT -j ACCEPT
exit $global_rc
diff --git a/iptables/tests/shell/testcases/iptables/0005-delete-rules_0 b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0
new file mode 100755
index 00000000..5038cbce
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# test for crash when comparing rules with standard target
+
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j DROP
+$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j REJECT
+[[ $? -eq 1 ]] || exit 1
+
+# test incorrect deletion of rules with deviating payload
+# in non-standard target
+
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j MARK --set-mark 23
+$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j MARK --set-mark 42
+[[ $? -eq 1 ]] || exit 1
diff --git a/iptables/tests/shell/testcases/iptables/0005-rule-replace_0 b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0
new file mode 100755
index 00000000..5a3e922e
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# test rule replacement
+
+set -e
+
+# show rules, drop uninteresting policy settings
+ipt_show() {
+ $XT_MULTI iptables -S | grep -v '^-P'
+}
+
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 1" -j ACCEPT
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 2" -j ACCEPT
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 3" -j ACCEPT
+
+$XT_MULTI iptables -R FORWARD 2 -m comment --comment "replaced 2" -j ACCEPT
+
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+$XT_MULTI iptables -R FORWARD 1 -m comment --comment "replaced 1" -j ACCEPT
+
+EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+$XT_MULTI iptables -R FORWARD 3 -m comment --comment "replaced 3" -j ACCEPT
+
+EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
+-A FORWARD -m comment --comment "replaced 3" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index b16f5fa6..36a2ec5f 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -433,10 +433,24 @@ void save_argv(void)
}
}
+struct xt_param_buf {
+ char buffer[1024];
+ int len;
+};
+
+static void add_param(struct xt_param_buf *param, const char *curchar)
+{
+ param->buffer[param->len++] = *curchar;
+ if (param->len >= sizeof(param->buffer))
+ xtables_error(PARAMETER_PROBLEM,
+ "Parameter too long!");
+}
+
void add_param_to_argv(char *parsestart, int line)
{
- int quote_open = 0, escaped = 0, param_len = 0;
- char param_buffer[1024], *curchar;
+ int quote_open = 0, escaped = 0;
+ struct xt_param_buf param = {};
+ char *curchar;
/* After fighting with strtok enough, here's now
* a 'real' parser. According to Rusty I'm now no
@@ -445,7 +459,7 @@ void add_param_to_argv(char *parsestart, int line)
for (curchar = parsestart; *curchar; curchar++) {
if (quote_open) {
if (escaped) {
- param_buffer[param_len++] = *curchar;
+ add_param(&param, curchar);
escaped = 0;
continue;
} else if (*curchar == '\\') {
@@ -455,7 +469,7 @@ void add_param_to_argv(char *parsestart, int line)
quote_open = 0;
*curchar = '"';
} else {
- param_buffer[param_len++] = *curchar;
+ add_param(&param, curchar);
continue;
}
} else {
@@ -471,36 +485,32 @@ void add_param_to_argv(char *parsestart, int line)
case ' ':
case '\t':
case '\n':
- if (!param_len) {
+ if (!param.len) {
/* two spaces? */
continue;
}
break;
default:
/* regular character, copy to buffer */
- param_buffer[param_len++] = *curchar;
-
- if (param_len >= sizeof(param_buffer))
- xtables_error(PARAMETER_PROBLEM,
- "Parameter too long!");
+ add_param(&param, curchar);
continue;
}
- param_buffer[param_len] = '\0';
+ param.buffer[param.len] = '\0';
/* check if table name specified */
- if ((param_buffer[0] == '-' &&
- param_buffer[1] != '-' &&
- strchr(param_buffer, 't')) ||
- (!strncmp(param_buffer, "--t", 3) &&
- !strncmp(param_buffer, "--table", strlen(param_buffer)))) {
+ if ((param.buffer[0] == '-' &&
+ param.buffer[1] != '-' &&
+ strchr(param.buffer, 't')) ||
+ (!strncmp(param.buffer, "--t", 3) &&
+ !strncmp(param.buffer, "--table", strlen(param.buffer)))) {
xtables_error(PARAMETER_PROBLEM,
"The -t option (seen in line %u) cannot be used in %s.\n",
line, xt_params->program_name);
}
- add_argv(param_buffer, 0);
- param_len = 0;
+ add_argv(param.buffer, 0);
+ param.len = 0;
}
}
@@ -653,12 +663,12 @@ const char *xt_parse_target(const char *targetname)
return targetname;
}
-void command_jump(struct iptables_command_state *cs)
+void command_jump(struct iptables_command_state *cs, const char *jumpto)
{
struct option *opts = xt_params->opts;
size_t size;
- cs->jumpto = xt_parse_target(optarg);
+ cs->jumpto = xt_parse_target(jumpto);
/* TRY_LOAD (may be chain name) */
cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 4265f989..ec31f2f0 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -177,6 +177,6 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
void command_match(struct iptables_command_state *cs);
const char *xt_parse_target(const char *targetname);
-void command_jump(struct iptables_command_state *cs);
+void command_jump(struct iptables_command_state *cs, const char *jumpto);
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 819e7e6c..d3cb9df8 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -144,6 +144,7 @@ static struct option original_opts[] = {
{ "help", 2, 0, 'h' },
{ "line-numbers", 0, 0, '0' },
{ "modprobe", 1, 0, 'M' },
+ { "set-counters", 1, 0, 'c' },
{ 0 }
};
@@ -481,11 +482,11 @@ exit_printhelp(void)
" --line-numbers print line numbers when listing\n"
" --exact -x expand numbers (display exact values)\n"
" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
+" --set-counters -c PKTS BYTES set the counter during insert/append\n"
"[!] --version -V print package version.\n");
printf(" opcode strings: \n");
for (i = 0; i < NUMOPCODES; i++)
- printf(" %d = %s\n", i + 1, opcodes[i]);
+ printf(" %d = %s\n", i + 1, arp_opcodes[i]);
printf(
" hardware type string: 1 = Ethernet\n"
" protocol type string: 0x800 = IPv4\n");
@@ -825,7 +826,7 @@ append_entry(struct nft_handle *h,
for (j = 0; j < ndaddrs; j++) {
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table, cs, 0,
+ ret = nft_rule_append(h, chain, table, cs, NULL,
verbose);
} else {
ret = nft_rule_insert(h, chain, table, cs,
@@ -909,8 +910,12 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
{
struct iptables_command_state cs = {
.jumpto = "",
- .arp.arp.arhln = 6,
- .arp.arp.arhrd = htons(ARPHRD_ETHER),
+ .arp.arp = {
+ .arhln = 6,
+ .arhln_mask = 255,
+ .arhrd = htons(ARPHRD_ETHER),
+ .arhrd_mask = 65535,
+ },
};
int invert = 0;
unsigned int nsaddrs = 0, ndaddrs = 0;
@@ -1121,7 +1126,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
int i;
for (i = 0; i < NUMOPCODES; i++)
- if (!strcasecmp(opcodes[i], optarg))
+ if (!strcasecmp(arp_opcodes[i], optarg))
break;
if (i == NUMOPCODES)
xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
@@ -1156,7 +1161,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
case 'j':
set_option(&options, OPT_JUMP, &cs.arp.arp.invflags,
invert);
- command_jump(&cs);
+ command_jump(&cs, optarg);
break;
case 'i':
diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c
index 84ce0b60..fb3daba0 100644
--- a/iptables/xtables-eb-standalone.c
+++ b/iptables/xtables-eb-standalone.c
@@ -54,7 +54,7 @@ int xtables_eb_main(int argc, char *argv[])
ret = nft_commit(&h);
if (!ret)
- fprintf(stderr, "%s\n", nft_strerror(errno));
+ fprintf(stderr, "ebtables: %s\n", nft_strerror(errno));
exit(!ret);
}
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index f98c3855..96b2730f 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -64,27 +64,6 @@ static int parse_rule_number(const char *rule)
return rule_nr;
}
-static const char *
-parse_target(const char *targetname)
-{
- const char *ptr;
-
- if (strlen(targetname) < 1)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target name (too short)");
-
- if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target '%s' (%d chars max)",
- targetname, EBT_CHAIN_MAXNAMELEN);
-
- for (ptr = targetname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target name `%s'", targetname);
- return targetname;
-}
-
static int get_current_chain(const char *chain)
{
if (strcmp(chain, "PREROUTING") == 0)
@@ -411,8 +390,7 @@ print_zero:
break;
} else if (c == 'j') {
ebt_check_option2(&flags, OPT_JUMP);
- cs.jumpto = parse_target(optarg);
- cs.target = ebt_command_jump(cs.jumpto);
+ command_jump(&cs, optarg);
break;
} else if (c == 's') {
ebt_check_option2(&flags, OPT_SOURCE);
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 87189144..bc71e122 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -139,27 +139,6 @@ static int parse_rule_number(const char *rule)
return rule_nr;
}
-static const char *
-parse_target(const char *targetname)
-{
- const char *ptr;
-
- if (strlen(targetname) < 1)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target name (too short)");
-
- if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target '%s' (%d chars max)",
- targetname, EBT_CHAIN_MAXNAMELEN);
-
- for (ptr = targetname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid target name `%s'", targetname);
- return targetname;
-}
-
static int
append_entry(struct nft_handle *h,
const char *chain,
@@ -171,7 +150,7 @@ append_entry(struct nft_handle *h,
int ret = 1;
if (append)
- ret = nft_rule_append(h, chain, table, cs, 0, verbose);
+ ret = nft_rule_append(h, chain, table, cs, NULL, verbose);
else
ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose);
@@ -291,23 +270,12 @@ struct option ebt_original_options[] =
{ 0 }
};
-static void __attribute__((__noreturn__,format(printf,2,3)))
-ebt_print_error(enum xtables_exittype status, const char *format, ...)
-{
- va_list l;
-
- va_start(l, format);
- vfprintf(stderr, format, l);
- fprintf(stderr, ".\n");
- va_end(l);
- exit(-1);
-}
-
+extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ebtables_globals = {
.option_offset = 0,
.program_version = IPTABLES_VERSION,
.orig_opts = ebt_original_options,
- .exit_err = ebt_print_error,
+ .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
@@ -376,29 +344,6 @@ static struct option *merge_options(struct option *oldopts,
return merge;
}
-/*
- * More glue code.
- */
-struct xtables_target *ebt_command_jump(const char *jumpto)
-{
- struct xtables_target *target;
- unsigned int verdict;
-
- /* Standard target? */
- if (!ebt_fill_target(jumpto, &verdict))
- jumpto = "standard";
-
- /* For ebtables, all targets are preloaded. Hence it is either in
- * xtables_targets or a custom chain to jump to, in which case
- * returning NULL is fine. */
- for (target = xtables_targets; target; target = target->next) {
- if (!strcmp(target->name, jumpto))
- break;
- }
-
- return target;
-}
-
static void print_help(const struct xtables_target *t,
const struct xtables_rule_match *m, const char *table)
{
@@ -855,7 +800,6 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
case 'E': /* Rename chain */
case 'X': /* Delete chain */
/* We allow -N chainname -P policy */
- /* XXX: Not in ebtables-compat */
if (command == 'N' && c == 'P') {
command = c;
optind--; /* No table specified */
@@ -1066,8 +1010,7 @@ print_zero:
} else if (c == 'j') {
ebt_check_option2(&flags, OPT_JUMP);
if (strcmp(optarg, "CONTINUE") != 0) {
- cs.jumpto = parse_target(optarg);
- cs.target = ebt_command_jump(cs.jumpto);
+ command_jump(&cs, optarg);
}
break;
} else if (c == 's') {
@@ -1281,17 +1224,16 @@ print_zero:
if (command == 'P') {
if (selected_chain < 0) {
- xtables_error(PARAMETER_PROBLEM,
- "Policy %s not allowed for user defined chains",
- policy);
- }
- if (strcmp(policy, "RETURN") == 0) {
- xtables_error(PARAMETER_PROBLEM,
- "Policy RETURN only allowed for user defined chains");
+ ret = ebt_set_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);
+ if (ret < 0)
+ xtables_error(PARAMETER_PROBLEM, "Wrong policy");
}
- ret = nft_chain_set(h, *table, chain, policy, NULL);
- if (ret < 0)
- xtables_error(PARAMETER_PROBLEM, "Wrong policy");
} else if (command == 'L') {
ret = list_rules(h, chain, *table, rule_nr,
0,
diff --git a/iptables/xtables-legacy-multi.c b/iptables/xtables-legacy-multi.c
index e68814dd..3b7905ff 100644
--- a/iptables/xtables-legacy-multi.c
+++ b/iptables/xtables-legacy-multi.c
@@ -1,3 +1,4 @@
+#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/iptables/xtables-legacy.8 b/iptables/xtables-legacy.8
index 5b4ab32a..6db7d2cb 100644
--- a/iptables/xtables-legacy.8
+++ b/iptables/xtables-legacy.8
@@ -67,7 +67,7 @@ iptables-legacy-save and checking for any differences in output.
.B xtables\-monitor(8)
will need the
.B xtables\-nft(8)
-versions to work, it cannot display changes made using the.
+versions to work, it cannot display changes made using the
.B iptables-legacy
tools.
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 3b1ca777..f835c5e5 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -9,6 +9,7 @@
* This software has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <time.h>
#include <string.h>
@@ -403,26 +404,24 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
case IPPROTO_UDP:
if (len < 4)
break;
- printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport));
+ printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest));
break;
case IPPROTO_TCP:
if (len < sizeof(*tcph))
break;
- printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport));
- if (tcph->th_flags & (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG)) {
- if (tcph->th_flags & TH_SYN)
- printf("SYN ");
- if (tcph->th_flags & TH_ACK)
- printf("ACK ");
- if (tcph->th_flags & TH_FIN)
- printf("FIN ");
- if (tcph->th_flags & TH_RST)
- printf("RST ");
- if (tcph->th_flags & TH_PUSH)
- printf("PSH ");
- if (tcph->th_flags & TH_URG)
- printf("URG ");
- }
+ printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest));
+ if (tcph->syn)
+ printf("SYN ");
+ if (tcph->ack)
+ printf("ACK ");
+ if (tcph->fin)
+ printf("FIN ");
+ if (tcph->rst)
+ printf("RST ");
+ if (tcph->psh)
+ printf("PSH ");
+ if (tcph->urg)
+ printf("URG ");
break;
default:
break;
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index f5297740..a6a331d3 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -19,7 +19,7 @@
#include "nft-bridge.h"
#include <libnftnl/chain.h>
-static int counters, verbose, noflush;
+static int counters, verbose;
/* Keeping track of external matches and targets. */
static const struct option options[] = {
@@ -56,43 +56,27 @@ static void print_usage(const char *name, const char *version)
" [ --ipv6 ]\n", name);
}
-static struct nftnl_chain_list *get_chain_list(struct nft_handle *h)
+static struct nftnl_chain_list *get_chain_list(struct nft_handle *h,
+ const char *table)
{
struct nftnl_chain_list *chain_list;
- chain_list = nft_chain_list_get(h);
+ chain_list = nft_chain_list_get(h, table);
if (chain_list == NULL)
xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
return chain_list;
}
-static void chain_delete(struct nftnl_chain_list *clist, const char *curtable,
- const char *chain)
-{
- struct nftnl_chain *chain_obj;
-
- chain_obj = nft_chain_list_find(clist, curtable, chain);
- /* This chain has been found, delete from list. Later
- * on, unvisited chains will be purged out.
- */
- if (chain_obj != NULL) {
- nftnl_chain_list_del(chain_obj);
- nftnl_chain_free(chain_obj);
- }
-}
-
struct nft_xt_restore_cb restore_cb = {
.chain_list = get_chain_list,
.commit = nft_commit,
.abort = nft_abort,
.table_new = nft_table_new,
.table_flush = nft_table_flush,
- .chain_user_flush = nft_chain_user_flush,
- .chain_del = chain_delete,
.do_command = do_commandx,
.chain_set = nft_chain_set,
- .chain_user_add = nft_chain_user_add,
+ .chain_restore = nft_chain_restore,
};
static const struct xtc_ops xtc_ops = {
@@ -104,17 +88,13 @@ void xtables_restore_parse(struct nft_handle *h,
struct nft_xt_restore_cb *cb,
int argc, char *argv[])
{
+ const struct builtin_table *curtable = NULL;
char buffer[10240];
int in_table = 0;
- struct builtin_table *curtable = NULL;
const struct xtc_ops *ops = &xtc_ops;
- struct nftnl_chain_list *chain_list = NULL;
line = 0;
- if (cb->chain_list)
- chain_list = cb->chain_list(h);
-
/* Grab standard input. */
while (fgets(buffer, sizeof(buffer), p->in)) {
int ret = 0;
@@ -165,7 +145,9 @@ void xtables_restore_parse(struct nft_handle *h,
if (p->tablename && (strcmp(p->tablename, table) != 0))
continue;
- if (noflush == 0) {
+ nft_build_cache(h);
+
+ if (h->noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
if (cb->table_flush)
@@ -182,7 +164,6 @@ void xtables_restore_parse(struct nft_handle *h,
/* New chain. */
char *policy, *chain = NULL;
struct xt_counters count = {};
- bool chain_exists = false;
chain = strtok(buffer+1, " \t\n");
DEBUGP("line %u, chain '%s'\n", line, chain);
@@ -193,22 +174,6 @@ void xtables_restore_parse(struct nft_handle *h,
exit(1);
}
- if (noflush == 0) {
- if (cb->chain_del)
- cb->chain_del(chain_list, curtable->name,
- chain);
- } else if (nft_chain_list_find(chain_list,
- curtable->name, chain)) {
- chain_exists = true;
- /* Apparently -n still flushes existing user
- * defined chains that are redefined. Otherwise,
- * leave them as is.
- */
- if (cb->chain_user_flush)
- cb->chain_user_flush(h, chain_list,
- curtable->name, chain);
- }
-
if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
"Invalid chain name `%s' "
@@ -246,24 +211,22 @@ void xtables_restore_parse(struct nft_handle *h,
}
DEBUGP("Setting policy of chain %s to %s\n",
chain, policy);
- ret = 1;
-
- } else {
- if (!chain_exists &&
- cb->chain_user_add &&
- cb->chain_user_add(h, chain,
- curtable->name) < 0) {
- if (errno == EEXIST)
- continue;
-
- xtables_error(PARAMETER_PROBLEM,
- "cannot create chain "
- "'%s' (%s)\n", chain,
- strerror(errno));
- }
- continue;
+ } else if (cb->chain_restore(h, chain, curtable->name) < 0 &&
+ errno != EEXIST) {
+ xtables_error(PARAMETER_PROBLEM,
+ "cannot create chain "
+ "'%s' (%s)\n", chain,
+ strerror(errno));
+ } else if (h->family == NFPROTO_BRIDGE &&
+ !ebt_set_user_chain_policy(h, curtable->name,
+ chain, policy)) {
+ xtables_error(OTHER_PROBLEM,
+ "Can't set policy `%s'"
+ " on `%s' line %u: %s\n",
+ policy, chain, line,
+ ops->strerror(errno));
}
-
+ ret = 1;
} else if (in_table) {
int a;
char *pcnt = NULL;
@@ -359,7 +322,7 @@ void xtables_restore_parse(struct nft_handle *h,
static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
- struct builtin_table *tables;
+ const struct builtin_table *tables;
struct nft_handle h = {
.family = family,
.restore = true,
@@ -402,7 +365,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
IPTABLES_VERSION);
exit(0);
case 'n':
- noflush = 1;
+ h.noflush = 1;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -490,16 +453,21 @@ 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);
+}
+
struct nft_xt_restore_cb ebt_restore_cb = {
.chain_list = get_chain_list,
.commit = nft_commit,
.table_new = nft_table_new,
- .table_flush = nft_table_flush,
- .chain_user_flush = nft_chain_user_flush,
- .chain_del = chain_delete,
+ .table_flush = ebt_table_flush,
.do_command = do_commandeb,
.chain_set = nft_chain_set,
- .chain_user_add = nft_chain_user_add,
+ .chain_restore = nft_chain_restore,
};
static const struct option ebt_restore_options[] = {
@@ -512,6 +480,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
struct nft_xt_restore_parse p = {
.in = stdin,
};
+ bool noflush = false;
struct nft_handle h;
int c;
@@ -530,6 +499,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
}
nft_init_eb(&h, "ebtables-restore");
+ h.noflush = noflush;
xtables_restore_parse(&h, &p, &ebt_restore_cb, argc, argv);
nft_fini(&h);
@@ -541,11 +511,9 @@ struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
.table_new = nft_table_new,
.table_flush = nft_table_flush,
- .chain_user_flush = nft_chain_user_flush,
- .chain_del = chain_delete,
.do_command = do_commandarp,
.chain_set = nft_chain_set,
- .chain_user_add = nft_chain_user_add,
+ .chain_restore = nft_chain_restore,
};
int xtables_arp_restore_main(int argc, char *argv[])
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index bed3ee03..2cc5a7c7 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -73,7 +73,9 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters)
return 0;
}
- chain_list = nft_chain_list_get(h);
+ chain_list = nft_chain_list_get(h, tablename);
+ if (!chain_list)
+ return 0;
time_t now = time(NULL);
@@ -83,7 +85,7 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters)
/* Dump out chain names first,
* thereby preventing dependency conflicts */
- nft_chain_save(h, chain_list, tablename);
+ nft_chain_save(h, chain_list);
nft_rule_save(h, tablename, counters ? 0 : FMT_NOCOUNTS);
now = time(NULL);
@@ -103,8 +105,9 @@ do_output(struct nft_handle *h, const char *tablename, bool counters)
return !!ret;
}
- if (!nft_table_find(h, tablename)) {
- printf("Table `%s' does not exist\n", tablename);
+ if (!nft_table_find(h, tablename) &&
+ !nft_table_builtin_find(h, tablename)) {
+ fprintf(stderr, "Table `%s' does not exist\n", tablename);
return 1;
}
@@ -120,7 +123,7 @@ do_output(struct nft_handle *h, const char *tablename, bool counters)
static int
xtables_save_main(int family, const char *progname, int argc, char *argv[])
{
- struct builtin_table *tables;
+ const struct builtin_table *tables;
const char *tablename = NULL;
bool dump = false;
struct nft_handle h = {
@@ -184,7 +187,8 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
exit(0);
default:
fprintf(stderr,
- "Look at manual page `xtables-save.8' for more information.\n");
+ "Look at manual page `%s.8' for more information.\n",
+ prog_name);
exit(1);
}
}
@@ -257,7 +261,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters
return 0;
}
- chain_list = nft_chain_list_get(h);
+ chain_list = nft_chain_list_get(h, tablename);
if (first) {
now = time(NULL);
@@ -272,7 +276,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters
/* Dump out chain names first,
* thereby preventing dependency conflicts */
- nft_chain_save(h, chain_list, tablename);
+ nft_chain_save(h, chain_list);
nft_rule_save(h, tablename, format);
printf("\n");
return 0;
@@ -330,7 +334,8 @@ int xtables_eb_save_main(int argc_, char *argv_[])
exit(0);
default:
fprintf(stderr,
- "Look at manual page `xtables-save.8' for more information.\n");
+ "Look at manual page `%s.8' for more information.\n",
+ prog_name);
exit(1);
}
}
@@ -377,7 +382,8 @@ int xtables_arp_save_main(int argc, char **argv)
exit(0);
default:
fprintf(stderr,
- "Look at manual page `xtables-save.8' for more information.\n");
+ "Look at manual page `%s.8' for more information.\n",
+ prog_name);
exit(1);
}
}
@@ -399,7 +405,7 @@ int xtables_arp_save_main(int argc, char **argv)
}
printf("*filter\n");
- nft_chain_save(&h, nft_chain_list_get(&h), "filter");
+ nft_chain_save(&h, nft_chain_list_get(&h, "filter"));
nft_rule_save(&h, "filter", show_counters ? 0 : FMT_NOCOUNTS);
printf("\n");
nft_fini(&h);
diff --git a/iptables/xtables-translate.8 b/iptables/xtables-translate.8
index c40f9f02..3dc72760 100644
--- a/iptables/xtables-translate.8
+++ b/iptables/xtables-translate.8
@@ -22,11 +22,12 @@
.\" <http://www.gnu.org/licenses/>.
.\" %%%LICENSE_END
.\"
-.TH XTABLES-TRANSLATE 8 "Mar 16, 2018"
+.TH IPTABLES-TRANSLATE 8 "May 14, 2019"
.SH NAME
-xtables-translate \- translation tools to migrate from iptables to nftables
-
+iptables-translate \(em translation tool to migrate from iptables to nftables
+.P
+ip6tables-translate \(em translation tool to migrate from ip6tables to nftables
.SH DESCRIPTION
There is a set of tools to help the system administrator translate a given
ruleset from \fBiptables(8)\fP and \fBip6tables(8)\fP to \fBnftables(8)\fP.
@@ -123,7 +124,7 @@ To get up-to-date information about this, please head to
\fBhttps://wiki.nftables.org/\fP.
.SH SEE ALSO
-\fBnft(8)\fP, \fBxtables-compat(8)\fP
+\fBnft(8)\fP, \fBiptables(8)\fP
.SH AUTHORS
The nftables framework is written by the Netfilter project
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 849c53f3..eb35890a 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -329,8 +329,8 @@ static const struct option options[] = {
{ NULL },
};
-static int xlate_chain_user_add(struct nft_handle *h, const char *chain,
- const char *table)
+static int xlate_chain_user_restore(struct nft_handle *h, const char *chain,
+ const char *table)
{
printf("add chain %s %s %s\n", family2str[h->family], table, chain);
return 0;
@@ -416,7 +416,7 @@ static int dummy_compat_rev(const char *name, uint8_t rev, int opt)
static struct nft_xt_restore_cb cb_xlate = {
.table_new = xlate_table_new,
.chain_set = xlate_chain_set,
- .chain_user_add = xlate_chain_user_add,
+ .chain_restore = xlate_chain_user_restore,
.do_command = do_command_xlate,
.commit = commit,
.abort = commit,
@@ -426,7 +426,7 @@ static int xtables_xlate_main_common(struct nft_handle *h,
int family,
const char *progname)
{
- struct builtin_table *tables;
+ const struct builtin_table *tables;
int ret;
xtables_globals.program_name = progname;
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 24a6e234..44986a37 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -406,7 +406,7 @@ add_entry(const char *chain,
if (append) {
ret = nft_rule_append(h, chain, table,
- cs, 0,
+ cs, NULL,
verbose);
} else {
ret = nft_rule_insert(h, chain, table,
@@ -426,7 +426,7 @@ add_entry(const char *chain,
&d.mask.v6[j], sizeof(struct in6_addr));
if (append) {
ret = nft_rule_append(h, chain, table,
- cs, 0,
+ cs, NULL,
verbose);
} else {
ret = nft_rule_insert(h, chain, table,
@@ -820,7 +820,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
case 'j':
set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags,
cs->invert);
- command_jump(cs);
+ command_jump(cs, optarg);
break;
@@ -1064,18 +1064,11 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
p->chain);
}
- if (!p->xlate && !nft_chain_exists(h, p->table, p->chain))
- xtables_error(OTHER_PROBLEM,
- "Chain '%s' does not exist", 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);
}
- if (!p->xlate && p->command == CMD_NEW_CHAIN &&
- nft_chain_exists(h, p->table, p->chain))
- xtables_error(OTHER_PROBLEM, "Chain already exists");
}
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
@@ -1189,8 +1182,10 @@ 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)
+ if (cs.target) {
free(cs.target->t);
+ cs.target->t = NULL;
+ }
if (h->family == AF_INET) {
free(args.s.addr.v4);
diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am
index f789d34e..638295db 100644
--- a/libiptc/Makefile.am
+++ b/libiptc/Makefile.am
@@ -10,6 +10,6 @@ libiptc_la_SOURCES =
libiptc_la_LIBADD = libip4tc.la libip6tc.la
libiptc_la_LDFLAGS = -version-info 0:0:0 ${libiptc_LDFLAGS2}
libip4tc_la_SOURCES = libip4tc.c
-libip4tc_la_LDFLAGS = -version-info 1:0:1
+libip4tc_la_LDFLAGS = -version-info 2:0:0
libip6tc_la_SOURCES = libip6tc.c
-libip6tc_la_LDFLAGS = -version-info 1:0:1 ${libiptc_LDFLAGS2}
+libip6tc_la_LDFLAGS = -version-info 2:0:0 ${libiptc_LDFLAGS2}
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 68ebc27a..9326d615 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -2758,11 +2758,15 @@ TC_STRERROR(int err)
const struct xtc_ops TC_OPS = {
.commit = TC_COMMIT,
+ .init = TC_INIT,
.free = TC_FREE,
.builtin = TC_BUILTIN,
.is_chain = TC_IS_CHAIN,
.flush_entries = TC_FLUSH_ENTRIES,
.create_chain = TC_CREATE_CHAIN,
+ .first_chain = TC_FIRST_CHAIN,
+ .next_chain = TC_NEXT_CHAIN,
+ .get_policy = TC_GET_POLICY,
.set_policy = TC_SET_POLICY,
.strerror = TC_STRERROR,
};
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index ea9bb102..895f6988 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -756,8 +756,24 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
}
for (ptr = xtables_targets; ptr; ptr = ptr->next) {
- if (extension_cmp(name, ptr->name, ptr->family))
+ if (extension_cmp(name, ptr->name, ptr->family)) {
+ struct xtables_target *clone;
+
+ /* First target of this type: */
+ if (ptr->t == NULL)
+ break;
+
+ /* Second and subsequent clones */
+ clone = xtables_malloc(sizeof(struct xtables_target));
+ memcpy(clone, ptr, sizeof(struct xtables_target));
+ clone->udata = NULL;
+ clone->tflags = 0;
+ /* This is a clone: */
+ clone->next = clone;
+
+ ptr = clone;
break;
+ }
}
#ifndef NO_SHARED_LIBS
diff --git a/release.sh b/release.sh
deleted file mode 100644
index 7c76423e..00000000
--- a/release.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /bin/sh
-#
-set -e
-
-VERSION=1.4.7
-PREV_VERSION=1.4.6
-TMPDIR=/tmp/ipt-release
-IPTDIR="$TMPDIR/iptables-$VERSION"
-
-PATCH="patch-iptables-$PREV_VERSION-$VERSION.bz2";
-TARBALL="iptables-$VERSION.tar.bz2";
-CHANGELOG="changes-iptables-$PREV_VERSION-$VERSION.txt";
-
-mkdir -p "$TMPDIR"
-git shortlog "v$PREV_VERSION..v$VERSION" > "$TMPDIR/$CHANGELOG"
-git diff "v$PREV_VERSION..v$VERSION" | bzip2 > "$TMPDIR/$PATCH"
-git archive --prefix="iptables-$VERSION/" "v$VERSION" | tar -xC "$TMPDIR/"
-
-cd "$IPTDIR" && {
- sh autogen.sh
- cd ..
-}
-
-tar -cjf "$TARBALL" "iptables-$VERSION";
-gpg -u "Netfilter Core Team" -sb "$TARBALL";
-md5sum "$TARBALL" >"$TARBALL.md5sum";
-sha1sum "$TARBALL" >"$TARBALL.sha1sum";
-
-gpg -u "Netfilter Core Team" -sb "$PATCH";
-md5sum "$PATCH" >"$PATCH.md5sum";
-sha1sum "$PATCH" >"$PATCH.sha1sum";
diff --git a/utils/.gitignore b/utils/.gitignore
index 7c6afbf4..6300812b 100644
--- a/utils/.gitignore
+++ b/utils/.gitignore
@@ -1,3 +1,4 @@
/nfnl_osf
/nfnl_osf.8
/nfbpf_compile
+/nfbpf_compile.8
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 80029e30..d09a6974 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -17,6 +17,7 @@ nfnl_osf_LDADD = ${libnfnetlink_LIBS}
endif
if ENABLE_BPFC
+man_MANS += nfbpf_compile.8
sbin_PROGRAMS += nfbpf_compile
nfbpf_compile_LDADD = -lpcap
endif
@@ -26,4 +27,4 @@ sbin_PROGRAMS += nfsynproxy
nfsynproxy_LDADD = -lpcap
endif
-CLEANFILES = nfnl_osf.8
+CLEANFILES = nfnl_osf.8 nfbpf_compile.8
diff --git a/utils/nfbpf_compile.8.in b/utils/nfbpf_compile.8.in
new file mode 100644
index 00000000..d02979a5
--- /dev/null
+++ b/utils/nfbpf_compile.8.in
@@ -0,0 +1,70 @@
+.TH NFBPF_COMPILE 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
+
+.SH NAME
+nfbpf_compile \- generate bytecode for use with xt_bpf
+.SH SYNOPSIS
+
+.ad l
+.in +8
+.ti -8
+.B nfbpf_compile
+[
+.I LLTYPE
+]
+.I PROGRAM
+
+.ti -8
+.I LLTYPE
+:= {
+.BR EN10MB " | " RAW " | " SLIP " | "
+.I ...
+}
+
+.SH DESCRIPTION
+The
+.B nfbpf_compile
+utility aids in generating BPF byte code suitable for passing to
+the iptables
+.B bpf
+match.
+
+.SH OPTIONS
+
+.TP
+.I LLTYPE
+Link-layer header type to operate on. This is a name as defined in
+.RB < pcap/dlt.h >
+but with the leading
+.B DLT_
+prefix stripped. For use with iptables,
+.B RAW
+should be the right choice (it's also the default if not specified).
+
+.TP
+.I PROGRAM
+The BPF expression to compile, see
+.BR pcap-filter (7)
+for a description of the language.
+
+.SH EXIT STATUS
+The program returns 0 on success, 1 otherwise.
+
+.SH EXAMPLE
+Match incoming TCP packets with size bigger than 100 bytes:
+.P
+.in +8
+.EE
+bpf=$(nfbpf_compile 'tcp and greater 100')
+.br
+iptables -A INPUT -m bpf --bytecode "$bpf" -j ACCEPT
+.RE
+.P
+The description of
+.B bpf
+match in
+.BR iptables-extensions (8)
+lists a few more examples.
+
+.SH SEE ALSO
+.BR iptables-extensions (8),
+.BR pcap-filter (7)
diff --git a/xlate-test.py b/xlate-test.py
index f365a700..4c014f9b 100755
--- a/xlate-test.py
+++ b/xlate-test.py
@@ -8,6 +8,7 @@ import argparse
from subprocess import Popen, PIPE
keywords = ("iptables-translate", "ip6tables-translate", "ebtables-translate")
+xtables_nft_multi = 'xtables-nft-multi'
if sys.stdout.isatty():
colors = {"magenta": "\033[95m", "green": "\033[92m", "yellow": "\033[93m",
@@ -33,6 +34,7 @@ def green(string):
def run_test(name, payload):
+ global xtables_nft_multi
test_passed = True
tests = passed = failed = errors = 0
result = []
@@ -40,7 +42,7 @@ def run_test(name, payload):
for line in payload:
if line.startswith(keywords):
tests += 1
- process = Popen([ os.path.abspath(os.path.curdir) + "/iptables/xtables-nft-multi" ] + shlex.split(line), stdout=PIPE, stderr=PIPE)
+ process = Popen([ xtables_nft_multi ] + shlex.split(line), stdout=PIPE, stderr=PIPE)
(output, error) = process.communicate()
if process.returncode == 0:
translation = output.decode("utf-8").rstrip(" \n")
@@ -86,8 +88,12 @@ def load_test_files():
print("%d test files, %d tests, %d tests passed, %d tests failed, %d errors" % (test_files, total_tests, total_passed, total_failed, total_error))
def main():
- os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions"))
- os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), os.getenv("PATH")))
+ global xtables_nft_multi
+ if not args.host:
+ os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions"))
+ xtables_nft_multi = os.path.abspath(os.path.curdir) \
+ + '/iptables/' + xtables_nft_multi
+
if args.test:
if not args.test.endswith(".txlate"):
args.test += ".txlate"
@@ -101,6 +107,8 @@ def main():
parser = argparse.ArgumentParser()
+parser.add_argument('-H', '--host', action='store_true',
+ help='Run tests against installed binaries')
parser.add_argument("test", nargs="?", help="run only the specified test file")
args = parser.parse_args()
main()