From 30c1d443896311e69762d6b51b63908ec602574f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 28 Jan 2021 01:09:56 +0100 Subject: ebtables: Exit gracefully on invalid table names Users are able to cause program abort by passing a table name that doesn't exist: | # ebtables-nft -t dummy -P INPUT ACCEPT | ebtables: nft-cache.c:455: fetch_chain_cache: Assertion `t' failed. | Aborted Avoid this by checking table existence just like iptables-nft does upon parsing '-t' optarg. Since the list of tables is known and fixed, checking the given name's length is pointless. So just drop that check in return. With this patch in place, output looks much better: | # ebtables-nft -t dummy -P INPUT ACCEPT | ebtables v1.8.7 (nf_tables): table 'dummy' does not exist | Perhaps iptables or your kernel needs to be upgraded. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index cfa9317c..5bb34d6d 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -914,10 +914,10 @@ print_zero: xtables_error(PARAMETER_PROBLEM, "The -t option (seen in line %u) cannot be used in %s.\n", line, xt_params->program_name); - if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) - xtables_error(PARAMETER_PROBLEM, - "Table name length cannot exceed %d characters", - EBT_TABLE_MAXNAMELEN - 1); + if (!nft_table_builtin_find(h, optarg)) + xtables_error(VERSION_PROBLEM, + "table '%s' does not exist", + optarg); *table = optarg; table_set = true; break; -- cgit v1.2.3 From c94416573d8a97830aa1c9f8ea1bbbd17d4fddbe Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 16 Feb 2021 23:17:02 +0100 Subject: include: Drop libipulog.h The file is not included anywhere, also it seems outdated compared to the one in libnetfilter_log (which also holds the implementation). Signed-off-by: Phil Sutter Acked-by: Pablo Neira Ayuso --- include/libipulog/libipulog.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 include/libipulog/libipulog.h diff --git a/include/libipulog/libipulog.h b/include/libipulog/libipulog.h deleted file mode 100644 index 3f4cc2c7..00000000 --- a/include/libipulog/libipulog.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _LIBIPULOG_H -#define _LIBIPULOG_H - -/* libipulog.h,v 1.3 2001/05/21 19:15:16 laforge Exp */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FIXME: glibc sucks */ -#ifndef MSG_TRUNC -#define MSG_TRUNC 0x20 -#endif - -struct ipulog_handle; - -u_int32_t ipulog_group2gmask(u_int32_t group); - -struct ipulog_handle *ipulog_create_handle(u_int32_t gmask); - -void ipulog_destroy_handle(struct ipulog_handle *h); - -ssize_t ipulog_read(struct ipulog_handle *h, - unsigned char *buf, size_t len, int timeout); - -ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h, - const unsigned char *buf, - size_t len); - -void ipulog_perror(const char *s); - -#endif /* _LIBULOG_H */ -- cgit v1.2.3 From 5f1fcacebf9b4529950b6e3f88327049a0ea7cd2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 24 Feb 2021 11:08:02 +0100 Subject: iptables-nft: fix -Z option it zeroes the rule counters, so it needs fully populated cache. Add a test case to cover this. Fixes: 9d07514ac5c7a ("nft: calculate cache requirements from list of commands") Signed-off-by: Florian Westphal Acked-by: Phil Sutter --- iptables/nft-cmd.c | 2 +- .../shell/testcases/iptables/0007-zero-counters_0 | 64 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100755 iptables/tests/shell/testcases/iptables/0007-zero-counters_0 diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 5d33f1f0..f2b935c5 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -185,7 +185,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain, if (!cmd) return 0; - nft_cache_level_set(h, NFT_CL_CHAINS, cmd); + nft_cache_level_set(h, NFT_CL_RULES, cmd); return 1; } diff --git a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 new file mode 100755 index 00000000..36da1907 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 @@ -0,0 +1,64 @@ +#!/bin/bash + +RC=0 +COUNTR=$RANDOM$RANDOM + +$XT_MULTI iptables-restore -c < Date: Fri, 19 Feb 2021 16:54:57 +0100 Subject: nft: Fix bitwise expression avoidance detection Byte-boundary prefix detection was too sloppy: Any data following the first zero-byte was ignored. Add a follow-up loop making sure there are no stray bits in the designated host part. Fixes: 323259001d617 ("nft: Optimize class-based IP prefix matches") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 4 +++- .../shell/testcases/ip6tables/0004-address-masks_0 | 24 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100755 iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 10553ab2..c1664b50 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -166,7 +166,7 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, { const unsigned char *m = mask; bool bitwise = false; - int i; + int i, j; for (i = 0; i < len; i++) { if (m[i] != 0xff) { @@ -174,6 +174,8 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, break; } } + for (j = i + 1; !bitwise && j < len; j++) + bitwise = !!m[j]; if (!bitwise) len = i; diff --git a/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 new file mode 100755 index 00000000..7eb42f08 --- /dev/null +++ b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 @@ -0,0 +1,24 @@ +#!/bin/bash + +set -e + +$XT_MULTI ip6tables-restore < Date: Tue, 2 Mar 2021 14:50:07 +0100 Subject: xtables-translate: Fix translation of odd netmasks Iptables supports netmasks which are not prefixes to match on (or ignore) arbitrary bits in an address. Yet nftables' prefix notation is available for real prefixes only, so translation is not as trivial - print bitmask syntax for those cases. Signed-off-by: Phil Sutter --- extensions/generic.txlate | 48 +++++++++++++++++++++++++++++++++++++++++++++ extensions/libxt_standard.t | 12 ++++++++++++ iptables/nft-ipv4.c | 42 +++++++++++++++++++++++++++------------ iptables/nft-ipv6.c | 19 +++++++++++++++--- 4 files changed, 106 insertions(+), 15 deletions(-) diff --git a/extensions/generic.txlate b/extensions/generic.txlate index 0e256c37..9ae9a5b5 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -10,6 +10,54 @@ nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8 nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter +iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0 +nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter + +iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0 +nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter + +iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255 +nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter + +iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255 +nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter + +iptables-translate -I INPUT -s 0.0.0.0/16 +nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter + +iptables-translate -I INPUT -s 0.0.0.0/0 +nft insert rule ip filter INPUT counter + +iptables-translate -I INPUT ! -s 0.0.0.0/0 +nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter + +ip6tables-translate -I INPUT -i iifname -s feed::/16 +nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter + +ip6tables-translate -A INPUT -i iif+ ! -d feed::/16 +nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter + +ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00:: +nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter + +ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0 +nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter + +ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff +nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter + +ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff +nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter + +ip6tables-translate -I INPUT -s ::/16 +nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter + +ip6tables-translate -I INPUT -s ::/0 +nft insert rule ip6 filter INPUT counter + +ip6tables-translate -I INPUT ! -s ::/0 +nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter + ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0 nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t index 4313f7b7..56d6da2e 100644 --- a/extensions/libxt_standard.t +++ b/extensions/libxt_standard.t @@ -9,3 +9,15 @@ -j ACCEPT;=;OK -j RETURN;=;OK ! -p 0 -j ACCEPT;=;FAIL +-s 10.11.12.13/8;-s 10.0.0.0/8;OK +-s 10.11.12.13/9;-s 10.0.0.0/9;OK +-s 10.11.12.13/10;-s 10.0.0.0/10;OK +-s 10.11.12.13/11;-s 10.0.0.0/11;OK +-s 10.11.12.13/12;-s 10.0.0.0/12;OK +-s 10.11.12.13/30;-s 10.11.12.12/30;OK +-s 10.11.12.13/31;-s 10.11.12.12/31;OK +-s 10.11.12.13/32;-s 10.11.12.13/32;OK +-s 10.11.12.13/255.0.0.0;-s 10.0.0.0/8;OK +-s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK +-s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK +-s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index fdc15c6f..0d32a300 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -383,6 +383,32 @@ static void nft_ipv4_post_parse(int command, " source or destination IP addresses"); } +static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr, + const struct in_addr *mask, + bool inv, struct xt_xlate *xl) +{ + const char *op = inv ? "!= " : ""; + int cidr; + + if (!inv && !addr->s_addr && !mask->s_addr) + return; + + cidr = xtables_ipmask_to_cidr(mask); + switch (cidr) { + case -1: + /* inet_ntoa() is not reentrant */ + xt_xlate_add(xl, "%s & %s ", selector, inet_ntoa(*mask)); + xt_xlate_add(xl, "%s %s ", inv ? "!=" : "==", inet_ntoa(*addr)); + break; + case 32: + xt_xlate_add(xl, "%s %s%s ", selector, op, inet_ntoa(*addr)); + break; + default: + xt_xlate_add(xl, "%s %s%s/%d ", selector, op, inet_ntoa(*addr), + cidr); + } +} + static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl) { const struct iptables_command_state *cs = data; @@ -417,18 +443,10 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl) } } - if (cs->fw.ip.src.s_addr != 0) { - xt_xlate_add(xl, "ip saddr %s%s%s ", - cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "", - inet_ntoa(cs->fw.ip.src), - xtables_ipmask_to_numeric(&cs->fw.ip.smsk)); - } - if (cs->fw.ip.dst.s_addr != 0) { - xt_xlate_add(xl, "ip daddr %s%s%s ", - cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "", - inet_ntoa(cs->fw.ip.dst), - xtables_ipmask_to_numeric(&cs->fw.ip.dmsk)); - } + xlate_ipv4_addr("ip saddr", &cs->fw.ip.src, &cs->fw.ip.smsk, + cs->fw.ip.invflags & IPT_INV_SRCIP, xl); + xlate_ipv4_addr("ip daddr", &cs->fw.ip.dst, &cs->fw.ip.dmsk, + cs->fw.ip.invflags & IPT_INV_DSTIP, xl); ret = xlate_matches(cs, xl); if (!ret) diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 130ad3e6..46008fc5 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -337,14 +337,27 @@ static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr, const struct in6_addr *mask, int invert, struct xt_xlate *xl) { + const char *op = invert ? "!= " : ""; char addr_str[INET6_ADDRSTRLEN]; + int cidr; - if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr)) + if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr) && IN6_IS_ADDR_UNSPECIFIED(mask)) return; inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); - xt_xlate_add(xl, "%s %s%s%s ", selector, invert ? "!= " : "", addr_str, - xtables_ip6mask_to_numeric(mask)); + cidr = xtables_ip6mask_to_cidr(mask); + switch (cidr) { + case -1: + xt_xlate_add(xl, "%s & %s %s %s ", selector, + xtables_ip6addr_to_numeric(mask), + invert ? "!=" : "==", addr_str); + break; + case 128: + xt_xlate_add(xl, "%s %s%s ", selector, op, addr_str); + break; + default: + xt_xlate_add(xl, "%s %s%s/%d ", selector, op, addr_str, cidr); + } } static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl) -- cgit v1.2.3 From 831f57c7fbdc8d79e34b1d7d81ca6f6a8e6bae87 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 2 Mar 2021 15:07:13 +0100 Subject: libxtables: Simplify xtables_ipmask_to_cidr() a bit Reduce the whole mask matching into a single for-loop. No need for a shortcut, /32 masks will match in the first iteration. Signed-off-by: Phil Sutter --- libxtables/xtables.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index bc42ba82..fc3f6220 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -1430,16 +1430,11 @@ int xtables_ipmask_to_cidr(const struct in_addr *mask) int i; maskaddr = ntohl(mask->s_addr); - /* shortcut for /32 networks */ - if (maskaddr == 0xFFFFFFFFL) - return 32; - - i = 32; - bits = 0xFFFFFFFEL; - while (--i >= 0 && maskaddr != bits) - bits <<= 1; - if (i >= 0) - return i; + + for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) { + if (bits == maskaddr) + return i; + } /* this mask cannot be converted to CIDR notation */ return -1; -- cgit v1.2.3 From 18e334da7363ba186edb1700056e26ded27ca5ba Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 1 Apr 2021 16:47:07 +0300 Subject: extensions: libxt_conntrack: use bitops for state negation Currently, state_xlate_print function prints statemask as comma-separated sequence of enabled statemask flags. But if we have inverted conntrack ctstate condition then we have to use more complex expression because nft not supports syntax like "ct state != related,established". Reproducer: $ iptables -A INPUT -d 127.0.0.1/32 -p tcp -m conntrack ! --ctstate RELATED,ESTABLISHED -j DROP $ nft list ruleset ... meta l4proto tcp ip daddr 127.0.0.1 ct state != related,established counter packets 0 bytes 0 drop ... it will fail if we try to load this rule: $ nft -f nft_test ../nft_test:6:97-97: Error: syntax error, unexpected comma, expecting newline or semicolon Cc: Florian Westphal Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Florian Westphal --- extensions/libxt_conntrack.c | 38 +++++++++++++++++++++++++------------- extensions/libxt_conntrack.txlate | 5 ++++- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 7734509c..91f9e4aa 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1148,30 +1148,43 @@ static void state_save(const void *ip, const struct xt_entry_match *match) state_print_state(sinfo->statemask); } -static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask) +static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask, int inverted) { const char *sep = ""; + int one_flag_set; + + one_flag_set = !(statemask & (statemask - 1)); + + if (inverted && !one_flag_set) + xt_xlate_add(xl, "& ("); + else if (inverted) + xt_xlate_add(xl, "& "); if (statemask & XT_CONNTRACK_STATE_INVALID) { xt_xlate_add(xl, "%s%s", sep, "invalid"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { xt_xlate_add(xl, "%s%s", sep, "new"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { xt_xlate_add(xl, "%s%s", sep, "related"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { xt_xlate_add(xl, "%s%s", sep, "established"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { xt_xlate_add(xl, "%s%s", sep, "untracked"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } + + if (inverted && !one_flag_set) + xt_xlate_add(xl, ") == 0"); + else if (inverted) + xt_xlate_add(xl, " == 0"); } static int state_xlate(struct xt_xlate *xl, @@ -1180,9 +1193,9 @@ static int state_xlate(struct xt_xlate *xl, const struct xt_conntrack_mtinfo3 *sinfo = (const void *)params->match->data; - xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ? - "!= " : ""); - state_xlate_print(xl, sinfo->state_mask); + xt_xlate_add(xl, "ct state "); + state_xlate_print(xl, sinfo->state_mask, + sinfo->invert_flags & XT_CONNTRACK_STATE); xt_xlate_add(xl, " "); return 1; } @@ -1256,10 +1269,9 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat"); space = " "; } else { - xt_xlate_add(xl, "%sct state %s", space, - sinfo->invert_flags & XT_CONNTRACK_STATE ? - "!= " : ""); - state_xlate_print(xl, sinfo->state_mask); + xt_xlate_add(xl, "%sct state ", space); + state_xlate_print(xl, sinfo->state_mask, + sinfo->invert_flags & XT_CONNTRACK_STATE); space = " "; } } diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index d374f8a0..5ab85b17 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -2,7 +2,10 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCE nft add rule ip filter INPUT ct state new,related counter accept ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT -nft add rule ip6 filter INPUT ct state != new,related counter accept +nft add rule ip6 filter INPUT ct state & (new|related) == 0 counter accept + +ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT +nft add rule ip6 filter INPUT ct state & new == 0 counter accept iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT nft add rule ip filter INPUT ct original protocol 17 counter accept -- cgit v1.2.3 From 18d7535d8bce1a13668e9982f53cbd3e56e8c634 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 1 Apr 2021 16:47:08 +0300 Subject: extensions: libxt_conntrack: use bitops for status negation At the moment, status_xlate_print function prints statusmask as comma-separated sequence of enabled statusmask flags. But if we have inverted conntrack ctstatus condition then we have to use more complex expression (if more than one flag enabled) because nft not supports syntax like "ct status != expected,assured". Examples: ! --ctstatus CONFIRMED,ASSURED should be translated as ct status & (assured|confirmed) == 0 ! --ctstatus CONFIRMED can be translated as ct status & confirmed == 0 See also netfilter/xt_conntrack.c (conntrack_mt() function as a reference). Reproducer: $ iptables -A INPUT -d 127.0.0.1/32 -p tcp -m conntrack ! --ctstatus expected,assured -j DROP $ nft list ruleset ... meta l4proto tcp ip daddr 127.0.0.1 ct status != expected,assured counter packets 0 bytes 0 drop ... it will fail if we try to load this rule: $ nft -f nft_test ../nft_test:6:97-97: Error: syntax error, unexpected comma, expecting newline or semicolon Cc: Florian Westphal Signed-off-by: Alexander Mikhalitsyn Signed-off-by: Florian Westphal --- extensions/libxt_conntrack.c | 30 +++++++++++++++++++++--------- extensions/libxt_conntrack.txlate | 8 +++++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 91f9e4aa..7f7b45ee 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1200,26 +1200,39 @@ static int state_xlate(struct xt_xlate *xl, return 1; } -static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask) +static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask, int inverted) { const char *sep = ""; + int one_flag_set; + + one_flag_set = !(statusmask & (statusmask - 1)); + + if (inverted && !one_flag_set) + xt_xlate_add(xl, "& ("); + else if (inverted) + xt_xlate_add(xl, "& "); if (statusmask & IPS_EXPECTED) { xt_xlate_add(xl, "%s%s", sep, "expected"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statusmask & IPS_SEEN_REPLY) { xt_xlate_add(xl, "%s%s", sep, "seen-reply"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statusmask & IPS_ASSURED) { xt_xlate_add(xl, "%s%s", sep, "assured"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } if (statusmask & IPS_CONFIRMED) { xt_xlate_add(xl, "%s%s", sep, "confirmed"); - sep = ","; + sep = inverted && !one_flag_set ? "|" : ","; } + + if (inverted && !one_flag_set) + xt_xlate_add(xl, ") == 0"); + else if (inverted) + xt_xlate_add(xl, " == 0"); } static void addr_xlate_print(struct xt_xlate *xl, @@ -1277,10 +1290,9 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_STATUS) { - xt_xlate_add(xl, "%sct status %s", space, - sinfo->invert_flags & XT_CONNTRACK_STATUS ? - "!= " : ""); - status_xlate_print(xl, sinfo->status_mask); + xt_xlate_add(xl, "%sct status ", space); + status_xlate_print(xl, sinfo->status_mask, + sinfo->invert_flags & XT_CONNTRACK_STATUS); space = " "; } diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index 5ab85b17..8cc7c504 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -35,7 +35,13 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT nft add rule ip filter INPUT ct status expected counter accept iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT -nft add rule ip filter INPUT ct status != confirmed counter accept +nft add rule ip filter INPUT ct status & confirmed == 0 counter accept + +iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT +nft add rule ip filter INPUT ct status & (assured|confirmed) == 0 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT +nft add rule ip filter INPUT ct status assured,confirmed counter accept iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT nft add rule ip filter INPUT ct expiration 3 counter accept -- cgit v1.2.3 From c5d9a723b5159a28f547b577711787295a14fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 2 Apr 2021 13:26:28 -0700 Subject: fix build for missing ETH_ALEN definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (this is needed at least with bionic) Signed-off-by: Maciej Żenczykowski Signed-off-by: Florian Westphal --- libxtables/xtables.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index fc3f6220..e6edfb5b 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -45,6 +45,7 @@ #include #include /* INT_MAX in ip_tables.h/ip6_tables.h */ +#include /* ETH_ALEN */ #include #include #include -- cgit v1.2.3 From fdf64dcdace989589bac441805082e3b1fe6a915 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 25 Mar 2021 16:24:39 +0100 Subject: nft: cache: Sort chains on demand only Mandatory sorted insert of chains into cache significantly slows down restoring of large rulesets. Since the sorted list of user-defined chains is needed for listing and verbose output only, introduce nft_cache_sort_chains() and call it where needed. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 71 ++++++++++++++++++++++++++++++++++++++++--------- iptables/nft-cache.h | 1 + iptables/nft.c | 12 +++++++++ iptables/nft.h | 1 + iptables/xtables-save.c | 1 + 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 6b6e6da4..8fbf9727 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -223,24 +223,67 @@ int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t, h->cache->table[t->type].base_chains[hooknum] = nc; } else { - struct nft_chain_list *clist = h->cache->table[t->type].chains; - struct list_head *pos = &clist->list; - struct nft_chain *cur; - const char *n; - - list_for_each_entry(cur, &clist->list, head) { - n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME); - if (strcmp(cname, n) <= 0) { - pos = &cur->head; - break; - } - } - list_add_tail(&nc->head, pos); + list_add_tail(&nc->head, + &h->cache->table[t->type].chains->list); } hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname)); return 0; } +static void __nft_chain_list_sort(struct list_head *list, + int (*cmp)(struct nft_chain *a, + struct nft_chain *b)) +{ + struct nft_chain *pivot, *cur, *sav; + LIST_HEAD(sublist); + + if (list_empty(list)) + return; + + /* grab first item as pivot (dividing) value */ + pivot = list_entry(list->next, struct nft_chain, head); + list_del(&pivot->head); + + /* move any smaller value into sublist */ + list_for_each_entry_safe(cur, sav, list, head) { + if (cmp(pivot, cur) > 0) { + list_del(&cur->head); + list_add_tail(&cur->head, &sublist); + } + } + /* conquer divided */ + __nft_chain_list_sort(&sublist, cmp); + __nft_chain_list_sort(list, cmp); + + /* merge divided and pivot again */ + list_add_tail(&pivot->head, &sublist); + list_splice(&sublist, list); +} + +static int nft_chain_cmp_byname(struct nft_chain *a, struct nft_chain *b) +{ + const char *aname = nftnl_chain_get_str(a->nftnl, NFTNL_CHAIN_NAME); + const char *bname = nftnl_chain_get_str(b->nftnl, NFTNL_CHAIN_NAME); + + return strcmp(aname, bname); +} + +int nft_cache_sort_chains(struct nft_handle *h, const char *table) +{ + const struct builtin_table *t = nft_table_builtin_find(h, table); + + if (!t) + return -1; + + if (h->cache->table[t->type].sorted) + return 0; + + __nft_chain_list_sort(&h->cache->table[t->type].chains->list, + nft_chain_cmp_byname); + h->cache->table[t->type].sorted = true; + return 0; +} + struct nftnl_chain_list_cb_data { struct nft_handle *h; const struct builtin_table *t; @@ -663,6 +706,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c, flush_base_chain_cache(c->table[table->type].base_chains); nft_chain_foreach(h, tablename, __flush_chain_cache, NULL); + c->table[table->type].sorted = false; if (c->table[table->type].sets) nftnl_set_list_foreach(c->table[table->type].sets, @@ -678,6 +722,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c, if (c->table[i].chains) { nft_chain_list_free(c->table[i].chains); c->table[i].chains = NULL; + c->table[i].sorted = false; } if (c->table[i].sets) { diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h index 20d96bee..58a01526 100644 --- a/iptables/nft-cache.h +++ b/iptables/nft-cache.h @@ -16,6 +16,7 @@ int flush_rule_cache(struct nft_handle *h, const char *table, void nft_cache_build(struct nft_handle *h); int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t, struct nftnl_chain *c); +int nft_cache_sort_chains(struct nft_handle *h, const char *table); struct nft_chain * nft_chain_find(struct nft_handle *h, const char *table, const char *chain); diff --git a/iptables/nft.c b/iptables/nft.c index bde4ca72..8b14daea 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1754,6 +1754,8 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, return 1; } + nft_cache_sort_chains(h, table); + ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d); /* the core expects 1 for success and 0 for error */ @@ -1900,6 +1902,9 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, goto out; } + if (verbose) + nft_cache_sort_chains(h, table); + ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d); out: /* the core expects 1 for success and 0 for error */ @@ -2437,6 +2442,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, return 1; } + nft_cache_sort_chains(h, table); + if (ops->print_table_header) ops->print_table_header(table); @@ -2540,6 +2547,8 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, return nft_rule_list_cb(c, &d); } + nft_cache_sort_chains(h, table); + /* Dump policies and custom chains first */ nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters); @@ -3431,6 +3440,9 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, goto err; } + if (verbose) + nft_cache_sort_chains(h, table); + ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d); err: /* the core expects 1 for success and 0 for error */ diff --git a/iptables/nft.h b/iptables/nft.h index 0910f82a..4ac7e009 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -44,6 +44,7 @@ struct nft_cache { struct nft_chain_list *chains; struct nftnl_set_list *sets; bool exists; + bool sorted; } table[NFT_TABLE_MAX]; }; diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index d7901c65..cfce0472 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -87,6 +87,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data) printf("*%s\n", tablename); /* Dump out chain names first, * thereby preventing dependency conflicts */ + nft_cache_sort_chains(h, tablename); nft_chain_foreach(h, tablename, nft_chain_save, h); nft_rule_save(h, tablename, d->format); if (d->commit) -- cgit v1.2.3 From a3e81c62e8c5abb4158f1f66df6bbcffd1b33240 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 6 Apr 2021 10:51:20 +0200 Subject: nft: Increase BATCH_PAGE_SIZE to support huge rulesets In order to support the same ruleset sizes as legacy iptables, the kernel's limit of 1024 iovecs has to be overcome. Therefore increase each iovec's size from 128KB to 2MB. While being at it, add a log message for failing sendmsg() call. This is not supposed to happen, even if the transaction fails. Yet if it does, users are left with only a "line XXX failed" message (with line number being the COMMIT line). Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- iptables/nft.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 8b14daea..f1deb82f 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -88,11 +88,11 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, #define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize()) -/* selected batch page is 256 Kbytes long to load ruleset of - * half a million rules without hitting -EMSGSIZE due to large - * iovec. +/* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M + * rules matching on source and destination address as well as input and output + * interfaces. This is what legacy iptables supports. */ -#define BATCH_PAGE_SIZE getpagesize() * 32 +#define BATCH_PAGE_SIZE 2 * 1024 * 1024 static struct nftnl_batch *mnl_batch_init(void) { @@ -220,8 +220,10 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds) int err = 0; ret = mnl_nft_socket_sendmsg(h, numcmds); - if (ret == -1) + if (ret == -1) { + fprintf(stderr, "sendmsg() failed: %s\n", strerror(errno)); return -1; + } FD_ZERO(&readfds); FD_SET(fd, &readfds); -- cgit v1.2.3 From 9084ef290a39d42d802204c9e80d7263c2c95ea2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 24 Mar 2021 16:18:58 +0100 Subject: extensions: sctp: Explain match types in man page They weren't mentioned at all. Signed-off-by: Phil Sutter --- extensions/libxt_sctp.man | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man index 3779d05a..3e5ffa09 100644 --- a/extensions/libxt_sctp.man +++ b/extensions/libxt_sctp.man @@ -8,6 +8,17 @@ This module matches Stream Control Transmission Protocol headers. The flag letter in upper case indicates that the flag is to match if set, in the lower case indicates to match if unset. +Match types: +.TP +all +Match if all given chunk types are present and flags match. +.TP +any +Match if any of the given chunk types is present with given flags. +.TP +only +Match if only the given chunk types are present with given flags and none are missing. + Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN chunk type available flags -- cgit v1.2.3 From acac2dbe64e5120394fa715bb5fe95c42d08b8b3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Apr 2021 09:12:53 +0200 Subject: Eliminate inet_aton() and inet_ntoa() Both functions are obsolete, replace them by equivalent calls to inet_pton() and inet_ntop(). Signed-off-by: Phil Sutter --- extensions/libebt_among.c | 6 ++++-- iptables/nft-ipv4.c | 23 ++++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c index 2b9a1b65..7eb898f9 100644 --- a/extensions/libebt_among.c +++ b/extensions/libebt_among.c @@ -66,7 +66,7 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip) if (sep) { *sep = '\0'; - if (!inet_aton(sep + 1, &pair->in)) + if (!inet_pton(AF_INET, sep + 1, &pair->in)) xtables_error(PARAMETER_PROBLEM, "Invalid IP address '%s'\n", sep + 1); } @@ -194,6 +194,7 @@ static void __bramong_print(struct nft_among_pair *pairs, int cnt, bool inv, bool have_ip) { const char *isep = inv ? "! " : ""; + char abuf[INET_ADDRSTRLEN]; int i; for (i = 0; i < cnt; i++) { @@ -202,7 +203,8 @@ static void __bramong_print(struct nft_among_pair *pairs, printf("%s", ether_ntoa(&pairs[i].ether)); if (pairs[i].in.s_addr != INADDR_ANY) - printf("=%s", inet_ntoa(pairs[i].in)); + printf("=%s", inet_ntop(AF_INET, &pairs[i].in, + abuf, sizeof(abuf))); } printf(" "); } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 0d32a300..a5b835b1 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -136,7 +136,7 @@ static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) static const char *mask_to_str(uint32_t mask) { - static char mask_str[sizeof("255.255.255.255")]; + static char mask_str[INET_ADDRSTRLEN]; uint32_t bits, hmask = ntohl(mask); struct in_addr mask_addr = { .s_addr = mask, @@ -155,7 +155,7 @@ static const char *mask_to_str(uint32_t mask) if (i >= 0) sprintf(mask_str, "%u", i); else - sprintf(mask_str, "%s", inet_ntoa(mask_addr)); + inet_ntop(AF_INET, &mask_addr, mask_str, sizeof(mask_str)); return mask_str; } @@ -298,10 +298,13 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, static void save_ipv4_addr(char letter, const struct in_addr *addr, uint32_t mask, int invert) { + char addrbuf[INET_ADDRSTRLEN]; + if (!mask && !invert && !addr->s_addr) return; - printf("%s-%c %s/%s ", invert ? "! " : "", letter, inet_ntoa(*addr), + printf("%s-%c %s/%s ", invert ? "! " : "", letter, + inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)), mask_to_str(mask)); } @@ -387,25 +390,27 @@ static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr, const struct in_addr *mask, bool inv, struct xt_xlate *xl) { + char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN]; const char *op = inv ? "!= " : ""; int cidr; if (!inv && !addr->s_addr && !mask->s_addr) return; + inet_ntop(AF_INET, addr, abuf, sizeof(abuf)); + cidr = xtables_ipmask_to_cidr(mask); switch (cidr) { case -1: - /* inet_ntoa() is not reentrant */ - xt_xlate_add(xl, "%s & %s ", selector, inet_ntoa(*mask)); - xt_xlate_add(xl, "%s %s ", inv ? "!=" : "==", inet_ntoa(*addr)); + xt_xlate_add(xl, "%s & %s %s %s ", selector, + inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)), + inv ? "!=" : "==", abuf); break; case 32: - xt_xlate_add(xl, "%s %s%s ", selector, op, inet_ntoa(*addr)); + xt_xlate_add(xl, "%s %s%s ", selector, op, abuf); break; default: - xt_xlate_add(xl, "%s %s%s/%d ", selector, op, inet_ntoa(*addr), - cidr); + xt_xlate_add(xl, "%s %s%s/%d ", selector, op, abuf, cidr); } } -- cgit v1.2.3 From 1e984079817a3c804eae25dea937d63d18c57a6c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Apr 2021 10:02:34 +0200 Subject: nft-arp: Make use of ipv4_addr_to_string() This eliminates quite a bit of redundant code apart from also dropping use of obsolete function gethostbyaddr(). Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 99 +++++------------------------------------------------- iptables/xshared.c | 6 ++-- iptables/xshared.h | 3 ++ 3 files changed, 14 insertions(+), 94 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index c82ffdc9..2a9387a1 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -42,78 +42,6 @@ char *arp_opcodes[] = "ARP_NAK", }; -static char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -static char * -addr_to_host(const struct in_addr *addr) -{ - struct hostent *host; - - if ((host = gethostbyaddr((char *) addr, - sizeof(struct in_addr), AF_INET)) != NULL) - return (char *) host->h_name; - - return (char *) NULL; -} - -static char * -addr_to_network(const struct in_addr *addr) -{ - struct netent *net; - - if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) - return (char *) net->n_name; - - return (char *) NULL; -} - -static char * -addr_to_anyname(const struct in_addr *addr) -{ - char *name; - - if ((name = addr_to_host(addr)) != NULL || - (name = addr_to_network(addr)) != NULL) - return name; - - return addr_to_dotted(addr); -} - -static char * -mask_to_dotted(const struct in_addr *mask) -{ - int i; - static char buf[22]; - u_int32_t maskaddr, bits; - - maskaddr = ntohl(mask->s_addr); - - if (maskaddr == 0xFFFFFFFFL) - /* we don't want to see "/32" */ - return ""; - - i = 32; - bits = 0xFFFFFFFEL; - while (--i >= 0 && maskaddr != bits) - bits <<= 1; - if (i >= 0) - sprintf(buf, "/%d", i); - else - /* mask was not a decent combination of 1's and 0's */ - snprintf(buf, sizeof(buf), "/%s", addr_to_dotted(mask)); - - return buf; -} - static bool need_devaddr(struct arpt_devaddr_info *info) { int i; @@ -403,7 +331,6 @@ 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; @@ -450,15 +377,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs, } if (fw->arp.smsk.s_addr != 0L) { - printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP - ? "! " : ""); - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src))); - else - 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-s %s", sep, + fw->arp.invflags & IPT_INV_SRCIP ? "! " : "", + ipv4_addr_to_string(&fw->arp.src, + &fw->arp.smsk, format)); sep = " "; } @@ -476,15 +398,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs, after_devsrc: if (fw->arp.tmsk.s_addr != 0L) { - printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP - ? "! " : ""); - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt))); - else - 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("%s%s-d %s", sep, + fw->arp.invflags & IPT_INV_DSTIP ? "! " : "", + ipv4_addr_to_string(&fw->arp.tgt, + &fw->arp.tmsk, format)); sep = " "; } diff --git a/iptables/xshared.c b/iptables/xshared.c index 71f68990..9a1f465a 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -550,9 +550,9 @@ void debug_print_argv(struct argv_store *store) } #endif -static const char *ipv4_addr_to_string(const struct in_addr *addr, - const struct in_addr *mask, - unsigned int format) +const char *ipv4_addr_to_string(const struct in_addr *addr, + const struct in_addr *mask, + unsigned int format) { static char buf[BUFSIZ]; diff --git a/iptables/xshared.h b/iptables/xshared.h index 9159b2b1..1e86aba8 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -206,6 +206,9 @@ void debug_print_argv(struct argv_store *store); # define debug_print_argv(...) /* nothing */ #endif +const char *ipv4_addr_to_string(const struct in_addr *addr, + const struct in_addr *mask, + unsigned int format); void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format); void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format); -- cgit v1.2.3 From 616800af0da86d151cb695f1376d5ec6ede6fa72 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Apr 2021 15:28:59 +0200 Subject: extensions: SECMARK: Implement revision 1 The changed data structure for communication with kernel allows to exclude the field 'secid' which is populated on kernel side. Thus this fixes the formerly always failing extension comparison breaking rule check and rule delete by content. Signed-off-by: Phil Sutter --- extensions/libxt_SECMARK.c | 90 ++++++++++++++++++++++++++++-------- extensions/libxt_SECMARK.t | 4 ++ include/linux/netfilter/xt_SECMARK.h | 6 +++ 3 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 extensions/libxt_SECMARK.t diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c index 6ba86063..24249bd6 100644 --- a/extensions/libxt_SECMARK.c +++ b/extensions/libxt_SECMARK.c @@ -29,6 +29,13 @@ static const struct xt_option_entry SECMARK_opts[] = { XTOPT_TABLEEND, }; +static const struct xt_option_entry SECMARK_opts_v1[] = { + {.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(struct xt_secmark_target_info_v1, secctx)}, + XTOPT_TABLEEND, +}; + static void SECMARK_parse(struct xt_option_call *cb) { struct xt_secmark_target_info *info = cb->data; @@ -37,15 +44,23 @@ static void SECMARK_parse(struct xt_option_call *cb) info->mode = SECMARK_MODE_SEL; } -static void print_secmark(const struct xt_secmark_target_info *info) +static void SECMARK_parse_v1(struct xt_option_call *cb) +{ + struct xt_secmark_target_info_v1 *info = cb->data; + + xtables_option_parse(cb); + info->mode = SECMARK_MODE_SEL; +} + +static void print_secmark(__u8 mode, const char *secctx) { - switch (info->mode) { + switch (mode) { case SECMARK_MODE_SEL: - printf("selctx %s", info->secctx); + printf("selctx %s", secctx); break; - + default: - xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode); + xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", mode); } } @@ -56,7 +71,17 @@ static void SECMARK_print(const void *ip, const struct xt_entry_target *target, (struct xt_secmark_target_info*)(target)->data; printf(" SECMARK "); - print_secmark(info); + print_secmark(info->mode, info->secctx); +} + +static void SECMARK_print_v1(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + const struct xt_secmark_target_info_v1 *info = + (struct xt_secmark_target_info_v1 *)(target)->data; + + printf(" SECMARK "); + print_secmark(info->mode, info->secctx); } static void SECMARK_save(const void *ip, const struct xt_entry_target *target) @@ -65,24 +90,49 @@ static void SECMARK_save(const void *ip, const struct xt_entry_target *target) (struct xt_secmark_target_info*)target->data; printf(" --"); - print_secmark(info); + print_secmark(info->mode, info->secctx); } -static struct xtables_target secmark_target = { - .family = NFPROTO_UNSPEC, - .name = "SECMARK", - .version = XTABLES_VERSION, - .revision = 0, - .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)), - .help = SECMARK_help, - .print = SECMARK_print, - .save = SECMARK_save, - .x6_parse = SECMARK_parse, - .x6_options = SECMARK_opts, +static void SECMARK_save_v1(const void *ip, + const struct xt_entry_target *target) +{ + const struct xt_secmark_target_info_v1 *info = + (struct xt_secmark_target_info_v1 *)target->data; + + printf(" --"); + print_secmark(info->mode, info->secctx); +} + +static struct xtables_target secmark_tg_reg[] = { + { + .family = NFPROTO_UNSPEC, + .name = "SECMARK", + .version = XTABLES_VERSION, + .revision = 0, + .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)), + .help = SECMARK_help, + .print = SECMARK_print, + .save = SECMARK_save, + .x6_parse = SECMARK_parse, + .x6_options = SECMARK_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "SECMARK", + .version = XTABLES_VERSION, + .revision = 1, + .size = XT_ALIGN(sizeof(struct xt_secmark_target_info_v1)), + .userspacesize = XT_ALIGN(offsetof(struct xt_secmark_target_info_v1, secid)), + .help = SECMARK_help, + .print = SECMARK_print_v1, + .save = SECMARK_save_v1, + .x6_parse = SECMARK_parse_v1, + .x6_options = SECMARK_opts_v1, + } }; void _init(void) { - xtables_register_target(&secmark_target); + xtables_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg)); } diff --git a/extensions/libxt_SECMARK.t b/extensions/libxt_SECMARK.t new file mode 100644 index 00000000..39d4c093 --- /dev/null +++ b/extensions/libxt_SECMARK.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +*security +-j SECMARK --selctx system_u:object_r:firewalld_exec_t:s0;=;OK +-j SECMARK;;FAIL diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h index 989092bd..31760a28 100644 --- a/include/linux/netfilter/xt_SECMARK.h +++ b/include/linux/netfilter/xt_SECMARK.h @@ -19,4 +19,10 @@ struct xt_secmark_target_info { char secctx[SECMARK_SECCTX_MAX]; }; +struct xt_secmark_target_info_v1 { + __u8 mode; + char secctx[SECMARK_SECCTX_MAX]; + __u32 secid; +}; + #endif /*_XT_SECMARK_H_target */ -- cgit v1.2.3 From f647f61f273a15ed25307d7ca7a19cefc828c54c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 2 Nov 2020 12:05:44 +0100 Subject: xtables: Make invflags 16bit wide This is needed to merge with xtables-arp which has more builtin options and hence needs more bits in invflags. The only adjustment needed is the set_option() call for option '-j' which passed a pointer to cs->fw.ip.invflags. That field can't be changed, it belongs to uAPI. Though using args->invflags instead works fine, aside from that '-j' doesn't support inverting so this is merely a sanity check and no real invflag value assignment will happen. Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 2 +- iptables/xtables.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index da4ba9d2..cc8f3a79 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -190,7 +190,7 @@ struct xtables_args { int family; uint16_t proto; uint8_t flags; - uint8_t invflags; + uint16_t invflags; char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; bool goto_set; diff --git a/iptables/xtables.c b/iptables/xtables.c index 9779bd83..c3d82014 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -239,7 +239,7 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ static void -set_option(unsigned int *options, unsigned int option, uint8_t *invflg, +set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, int invert) { if (*options & option) @@ -692,7 +692,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], #endif case 'j': - set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, + set_option(&cs->options, OPT_JUMP, &args->invflags, cs->invert); command_jump(cs, optarg); break; -- cgit v1.2.3 From 3664249f520308e8d9ce6238374f08ac96aedbb6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 11 Nov 2020 17:16:40 +0100 Subject: xshared: Eliminate iptables_command_state->invert This field is not used by routines working with struct iptables_command_state: It is merely a temporary flag used by parsers to carry the '!' prefix until invflags have been populated (or error checking done if unsupported). Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 76 +++++++++++++++++++--------------------- iptables/iptables.c | 76 +++++++++++++++++++--------------------- iptables/xshared.c | 10 +++--- iptables/xshared.h | 5 ++- iptables/xtables-eb-translate.c | 1 - iptables/xtables-eb.c | 1 - iptables/xtables.c | 77 +++++++++++++++++++---------------------- 7 files changed, 113 insertions(+), 133 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index c95355b0..60db11b7 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -1083,6 +1083,7 @@ int do_command6(int argc, char *argv[], char **table, struct xtables_target *t; unsigned long long cnt; bool table_set = false; + bool invert = false; /* re-set optind to 0 in case do_command6 gets called * a second time */ @@ -1111,20 +1112,17 @@ int do_command6(int argc, char *argv[], char **table, * Command selection */ case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - cs.invert); + add_command(&command, CMD_APPEND, CMD_NONE, invert); chain = optarg; break; case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, - cs.invert); + add_command(&command, CMD_CHECK, CMD_NONE, invert); chain = optarg; break; case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - cs.invert); + add_command(&command, CMD_DELETE, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) { rulenum = parse_rulenumber(argv[optind++]); @@ -1133,8 +1131,7 @@ int do_command6(int argc, char *argv[], char **table, break; case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - cs.invert); + add_command(&command, CMD_REPLACE, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) rulenum = parse_rulenumber(argv[optind++]); @@ -1145,8 +1142,7 @@ int do_command6(int argc, char *argv[], char **table, break; case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - cs.invert); + add_command(&command, CMD_INSERT, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) rulenum = parse_rulenumber(argv[optind++]); @@ -1155,7 +1151,7 @@ int do_command6(int argc, char *argv[], char **table, case 'L': add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, cs.invert); + CMD_ZERO | CMD_ZERO_NUM, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1165,7 +1161,7 @@ int do_command6(int argc, char *argv[], char **table, case 'S': add_command(&command, CMD_LIST_RULES, - CMD_ZERO | CMD_ZERO_NUM, cs.invert); + CMD_ZERO | CMD_ZERO_NUM, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1174,8 +1170,7 @@ int do_command6(int argc, char *argv[], char **table, break; case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - cs.invert); + add_command(&command, CMD_FLUSH, CMD_NONE, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1183,7 +1178,7 @@ int do_command6(int argc, char *argv[], char **table, case 'Z': add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - cs.invert); + invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1195,14 +1190,13 @@ int do_command6(int argc, char *argv[], char **table, case 'N': parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - cs.invert); + add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - cs.invert); + invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1210,7 +1204,7 @@ int do_command6(int argc, char *argv[], char **table, case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - cs.invert); + invert); chain = optarg; if (xs_has_arg(argc, argv)) newname = argv[optind++]; @@ -1223,7 +1217,7 @@ int do_command6(int argc, char *argv[], char **table, case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, - cs.invert); + invert); chain = optarg; if (xs_has_arg(argc, argv)) policy = argv[optind++]; @@ -1249,7 +1243,7 @@ int do_command6(int argc, char *argv[], char **table, */ case 'p': set_option(&cs.options, OPT_PROTOCOL, &cs.fw6.ipv6.invflags, - cs.invert); + invert); /* Canonicalize into lower case */ for (cs.protocol = optarg; *cs.protocol; cs.protocol++) @@ -1274,20 +1268,20 @@ int do_command6(int argc, char *argv[], char **table, case 's': set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags, - cs.invert); + invert); shostnetworkmask = optarg; break; case 'd': set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags, - cs.invert); + invert); dhostnetworkmask = optarg; break; #ifdef IP6T_F_GOTO case 'g': set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, - cs.invert); + invert); cs.fw6.ipv6.flags |= IP6T_F_GOTO; cs.jumpto = xt_parse_target(optarg); break; @@ -1295,7 +1289,7 @@ int do_command6(int argc, char *argv[], char **table, case 'j': set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, - cs.invert); + invert); command_jump(&cs, optarg); break; @@ -1306,7 +1300,7 @@ int do_command6(int argc, char *argv[], char **table, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEIN, &cs.fw6.ipv6.invflags, - cs.invert); + invert); xtables_parse_interface(optarg, cs.fw6.ipv6.iniface, cs.fw6.ipv6.iniface_mask); @@ -1318,7 +1312,7 @@ int do_command6(int argc, char *argv[], char **table, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw6.ipv6.invflags, - cs.invert); + invert); xtables_parse_interface(optarg, cs.fw6.ipv6.outiface, cs.fw6.ipv6.outiface_mask); @@ -1327,7 +1321,7 @@ int do_command6(int argc, char *argv[], char **table, case 'v': if (!verbose) set_option(&cs.options, OPT_VERBOSE, - &cs.fw6.ipv6.invflags, cs.invert); + &cs.fw6.ipv6.invflags, invert); verbose++; break; @@ -1351,16 +1345,16 @@ int do_command6(int argc, char *argv[], char **table, break; case 'm': - command_match(&cs); + command_match(&cs, invert); break; case 'n': set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags, - cs.invert); + invert); break; case 't': - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); if (restore && table_set) @@ -1373,11 +1367,11 @@ int do_command6(int argc, char *argv[], char **table, case 'x': set_option(&cs.options, OPT_EXPANDED, &cs.fw6.ipv6.invflags, - cs.invert); + invert); break; case 'V': - if (cs.invert) + if (invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s (legacy)\n", @@ -1386,7 +1380,7 @@ int do_command6(int argc, char *argv[], char **table, case '0': set_option(&cs.options, OPT_LINENUMBERS, &cs.fw6.ipv6.invflags, - cs.invert); + invert); break; case 'M': @@ -1396,7 +1390,7 @@ int do_command6(int argc, char *argv[], char **table, case 'c': set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags, - cs.invert); + invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); if (bcnt) @@ -1434,11 +1428,11 @@ int do_command6(int argc, char *argv[], char **table, case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); - cs.invert = true; + invert = true; optarg[0] = '\0'; continue; } @@ -1446,16 +1440,16 @@ int do_command6(int argc, char *argv[], char **table, exit_tryhelp(2); default: - if (command_default(&cs, &ip6tables_globals) == 1) + if (command_default(&cs, &ip6tables_globals, invert)) /* * If new options were loaded, we must retry * getopt immediately and not allow - * cs.invert=false to be executed. + * invert=false to be executed. */ continue; break; } - cs.invert = false; + invert = false; } if (!wait && wait_interval_set) @@ -1481,7 +1475,7 @@ int do_command6(int argc, char *argv[], char **table, "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); diff --git a/iptables/iptables.c b/iptables/iptables.c index 7d618311..09760173 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -1078,6 +1078,7 @@ int do_command4(int argc, char *argv[], char **table, struct xtables_target *t; unsigned long long cnt; bool table_set = false; + bool invert = false; /* re-set optind to 0 in case do_command4 gets called * a second time */ @@ -1105,20 +1106,17 @@ int do_command4(int argc, char *argv[], char **table, * Command selection */ case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - cs.invert); + add_command(&command, CMD_APPEND, CMD_NONE, invert); chain = optarg; break; case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, - cs.invert); + add_command(&command, CMD_CHECK, CMD_NONE, invert); chain = optarg; break; case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - cs.invert); + add_command(&command, CMD_DELETE, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) { rulenum = parse_rulenumber(argv[optind++]); @@ -1127,8 +1125,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - cs.invert); + add_command(&command, CMD_REPLACE, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) rulenum = parse_rulenumber(argv[optind++]); @@ -1139,8 +1136,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - cs.invert); + add_command(&command, CMD_INSERT, CMD_NONE, invert); chain = optarg; if (xs_has_arg(argc, argv)) rulenum = parse_rulenumber(argv[optind++]); @@ -1149,7 +1145,7 @@ int do_command4(int argc, char *argv[], char **table, case 'L': add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, cs.invert); + CMD_ZERO | CMD_ZERO_NUM, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1159,7 +1155,7 @@ int do_command4(int argc, char *argv[], char **table, case 'S': add_command(&command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, cs.invert); + CMD_ZERO|CMD_ZERO_NUM, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1168,8 +1164,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - cs.invert); + add_command(&command, CMD_FLUSH, CMD_NONE, invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1177,7 +1172,7 @@ int do_command4(int argc, char *argv[], char **table, case 'Z': add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - cs.invert); + invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1189,14 +1184,13 @@ int do_command4(int argc, char *argv[], char **table, case 'N': parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - cs.invert); + add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - cs.invert); + invert); if (optarg) chain = optarg; else if (xs_has_arg(argc, argv)) chain = argv[optind++]; @@ -1204,7 +1198,7 @@ int do_command4(int argc, char *argv[], char **table, case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - cs.invert); + invert); chain = optarg; if (xs_has_arg(argc, argv)) newname = argv[optind++]; @@ -1217,7 +1211,7 @@ int do_command4(int argc, char *argv[], char **table, case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, - cs.invert); + invert); chain = optarg; if (xs_has_arg(argc, argv)) policy = argv[optind++]; @@ -1243,7 +1237,7 @@ int do_command4(int argc, char *argv[], char **table, */ case 'p': set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags, - cs.invert); + invert); /* Canonicalize into lower case */ for (cs.protocol = optarg; *cs.protocol; cs.protocol++) @@ -1260,20 +1254,20 @@ int do_command4(int argc, char *argv[], char **table, case 's': set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, - cs.invert); + invert); shostnetworkmask = optarg; break; case 'd': set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, - cs.invert); + invert); dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO case 'g': set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, - cs.invert); + invert); cs.fw.ip.flags |= IPT_F_GOTO; cs.jumpto = xt_parse_target(optarg); break; @@ -1281,7 +1275,7 @@ int do_command4(int argc, char *argv[], char **table, case 'j': set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, - cs.invert); + invert); command_jump(&cs, optarg); break; @@ -1292,7 +1286,7 @@ int do_command4(int argc, char *argv[], char **table, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags, - cs.invert); + invert); xtables_parse_interface(optarg, cs.fw.ip.iniface, cs.fw.ip.iniface_mask); @@ -1304,7 +1298,7 @@ int do_command4(int argc, char *argv[], char **table, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags, - cs.invert); + invert); xtables_parse_interface(optarg, cs.fw.ip.outiface, cs.fw.ip.outiface_mask); @@ -1312,14 +1306,14 @@ int do_command4(int argc, char *argv[], char **table, case 'f': set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags, - cs.invert); + invert); cs.fw.ip.flags |= IPT_F_FRAG; break; case 'v': if (!verbose) set_option(&cs.options, OPT_VERBOSE, - &cs.fw.ip.invflags, cs.invert); + &cs.fw.ip.invflags, invert); verbose++; break; @@ -1343,16 +1337,16 @@ int do_command4(int argc, char *argv[], char **table, break; case 'm': - command_match(&cs); + command_match(&cs, invert); break; case 'n': set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags, - cs.invert); + invert); break; case 't': - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); if (restore && table_set) @@ -1365,11 +1359,11 @@ int do_command4(int argc, char *argv[], char **table, case 'x': set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags, - cs.invert); + invert); break; case 'V': - if (cs.invert) + if (invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s (legacy)\n", @@ -1378,7 +1372,7 @@ int do_command4(int argc, char *argv[], char **table, case '0': set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags, - cs.invert); + invert); break; case 'M': @@ -1388,7 +1382,7 @@ int do_command4(int argc, char *argv[], char **table, case 'c': set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags, - cs.invert); + invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); if (bcnt) @@ -1426,11 +1420,11 @@ int do_command4(int argc, char *argv[], char **table, case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); - cs.invert = true; + invert = true; optarg[0] = '\0'; continue; } @@ -1438,12 +1432,12 @@ int do_command4(int argc, char *argv[], char **table, exit_tryhelp(2); default: - if (command_default(&cs, &iptables_globals) == 1) + if (command_default(&cs, &iptables_globals, invert)) /* cf. ip6tables.c */ continue; break; } - cs.invert = false; + invert = false; } if (!wait && wait_interval_set) @@ -1469,7 +1463,7 @@ int do_command4(int argc, char *argv[], char **table, "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (cs.invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); diff --git a/iptables/xshared.c b/iptables/xshared.c index 9a1f465a..afd7a9d6 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -115,7 +115,7 @@ struct xtables_match *load_proto(struct iptables_command_state *cs) } int command_default(struct iptables_command_state *cs, - struct xtables_globals *gl) + struct xtables_globals *gl, bool invert) { struct xtables_rule_match *matchp; struct xtables_match *m; @@ -124,7 +124,7 @@ int command_default(struct iptables_command_state *cs, (cs->target->parse != NULL || cs->target->x6_parse != NULL) && cs->c >= cs->target->option_offset && cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) { - xtables_option_tpcall(cs->c, cs->argv, cs->invert, + xtables_option_tpcall(cs->c, cs->argv, invert, cs->target, &cs->fw); return 0; } @@ -138,7 +138,7 @@ int command_default(struct iptables_command_state *cs, if (cs->c < matchp->match->option_offset || cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE) continue; - xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw); + xtables_option_mpcall(cs->c, cs->argv, invert, m, &cs->fw); return 0; } @@ -641,13 +641,13 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, printf(FMT("%-6s ", "out %s "), iface); } -void command_match(struct iptables_command_state *cs) +void command_match(struct iptables_command_state *cs, bool invert) { struct option *opts = xt_params->opts; struct xtables_match *m; size_t size; - if (cs->invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --match"); diff --git a/iptables/xshared.h b/iptables/xshared.h index 1e86aba8..af2a5adb 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -125,7 +125,6 @@ struct iptables_command_state { struct ip6t_entry fw6; struct arpt_entry arp; }; - int invert; int c; unsigned int options; struct xtables_rule_match *matches; @@ -154,7 +153,7 @@ extern void print_extension_helps(const struct xtables_target *, const struct xtables_rule_match *); extern const char *proto_to_name(uint8_t, int); extern int command_default(struct iptables_command_state *, - struct xtables_globals *); + struct xtables_globals *, bool invert); extern struct xtables_match *load_proto(struct iptables_command_state *); extern int subcmd_main(int, char **, const struct subcommand *); extern void xs_init_target(struct xtables_target *); @@ -215,7 +214,7 @@ void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format); void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, unsigned int format); -void command_match(struct iptables_command_state *cs); +void command_match(struct iptables_command_state *cs, bool invert); const char *xt_parse_target(const char *targetname); void command_jump(struct iptables_command_state *cs, const char *jumpto); diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 83ae77cb..04b3dfa0 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -220,7 +220,6 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char while ((c = getopt_long(argc, argv, "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { cs.c = c; - cs.invert = ebt_invert; switch (c) { case 'A': /* Add a rule */ case 'D': /* Delete a rule */ diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 5bb34d6d..6c58adaa 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -751,7 +751,6 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, while ((c = getopt_long(argc, argv, "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { cs.c = c; - cs.invert = ebt_invert; switch (c) { case 'A': /* Add a rule */ diff --git a/iptables/xtables.c b/iptables/xtables.c index c3d82014..73531ca8 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -240,7 +240,7 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) static void set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, - int invert) + bool invert) { if (*options & option) xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", @@ -466,6 +466,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], struct timeval wait_interval; struct xtables_target *t; bool table_set = false; + bool invert = false; int wait = 0; memset(cs, 0, sizeof(*cs)); @@ -499,20 +500,17 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], * Command selection */ case 'A': - add_command(&p->command, CMD_APPEND, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_APPEND, CMD_NONE, invert); p->chain = optarg; break; case 'C': - add_command(&p->command, CMD_CHECK, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_CHECK, CMD_NONE, invert); p->chain = optarg; break; case 'D': - add_command(&p->command, CMD_DELETE, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_DELETE, CMD_NONE, invert); p->chain = optarg; if (xs_has_arg(argc, argv)) { p->rulenum = parse_rulenumber(argv[optind++]); @@ -521,8 +519,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'R': - add_command(&p->command, CMD_REPLACE, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_REPLACE, CMD_NONE, invert); p->chain = optarg; if (xs_has_arg(argc, argv)) p->rulenum = parse_rulenumber(argv[optind++]); @@ -533,8 +530,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'I': - add_command(&p->command, CMD_INSERT, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_INSERT, CMD_NONE, invert); p->chain = optarg; if (xs_has_arg(argc, argv)) p->rulenum = parse_rulenumber(argv[optind++]); @@ -544,7 +540,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'L': add_command(&p->command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, cs->invert); + CMD_ZERO | CMD_ZERO_NUM, invert); if (optarg) p->chain = optarg; else if (xs_has_arg(argc, argv)) @@ -555,7 +551,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'S': add_command(&p->command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, cs->invert); + CMD_ZERO|CMD_ZERO_NUM, invert); if (optarg) p->chain = optarg; else if (xs_has_arg(argc, argv)) @@ -565,8 +561,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'F': - add_command(&p->command, CMD_FLUSH, CMD_NONE, - cs->invert); + add_command(&p->command, CMD_FLUSH, CMD_NONE, invert); if (optarg) p->chain = optarg; else if (xs_has_arg(argc, argv)) @@ -575,7 +570,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'Z': add_command(&p->command, CMD_ZERO, - CMD_LIST|CMD_LIST_RULES, cs->invert); + CMD_LIST|CMD_LIST_RULES, invert); if (optarg) p->chain = optarg; else if (xs_has_arg(argc, argv)) @@ -596,13 +591,13 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "chain name may not clash " "with target name\n"); add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE, - cs->invert); + invert); p->chain = optarg; break; case 'X': add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE, - cs->invert); + invert); if (optarg) p->chain = optarg; else if (xs_has_arg(argc, argv)) @@ -611,7 +606,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'E': add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE, - cs->invert); + invert); p->chain = optarg; if (xs_has_arg(argc, argv)) p->newname = argv[optind++]; @@ -624,7 +619,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'P': add_command(&p->command, CMD_SET_POLICY, CMD_NONE, - cs->invert); + invert); p->chain = optarg; if (xs_has_arg(argc, argv)) p->policy = argv[optind++]; @@ -652,7 +647,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], */ case 'p': set_option(&cs->options, OPT_PROTOCOL, - &args->invflags, cs->invert); + &args->invflags, invert); /* Canonicalize into lower case */ for (cs->protocol = optarg; *cs->protocol; cs->protocol++) @@ -672,20 +667,20 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 's': set_option(&cs->options, OPT_SOURCE, - &args->invflags, cs->invert); + &args->invflags, invert); args->shostnetworkmask = optarg; break; case 'd': set_option(&cs->options, OPT_DESTINATION, - &args->invflags, cs->invert); + &args->invflags, invert); args->dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO case 'g': set_option(&cs->options, OPT_JUMP, &args->invflags, - cs->invert); + invert); args->goto_set = true; cs->jumpto = xt_parse_target(optarg); break; @@ -693,7 +688,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'j': set_option(&cs->options, OPT_JUMP, &args->invflags, - cs->invert); + invert); command_jump(cs, optarg); break; @@ -704,7 +699,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "Empty interface is likely to be " "undesired"); set_option(&cs->options, OPT_VIANAMEIN, - &args->invflags, cs->invert); + &args->invflags, invert); xtables_parse_interface(optarg, args->iniface, args->iniface_mask); @@ -716,7 +711,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "Empty interface is likely to be " "undesired"); set_option(&cs->options, OPT_VIANAMEOUT, - &args->invflags, cs->invert); + &args->invflags, invert); xtables_parse_interface(optarg, args->outiface, args->outiface_mask); @@ -729,28 +724,28 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "use -m frag instead"); } set_option(&cs->options, OPT_FRAGMENT, &args->invflags, - cs->invert); + invert); args->flags |= IPT_F_FRAG; break; case 'v': if (!p->verbose) set_option(&cs->options, OPT_VERBOSE, - &args->invflags, cs->invert); + &args->invflags, invert); p->verbose++; break; case 'm': - command_match(cs); + command_match(cs, invert); break; case 'n': set_option(&cs->options, OPT_NUMERIC, &args->invflags, - cs->invert); + invert); break; case 't': - if (cs->invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); if (p->restore && table_set) @@ -767,11 +762,11 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'x': set_option(&cs->options, OPT_EXPANDED, &args->invflags, - cs->invert); + invert); break; case 'V': - if (cs->invert) + if (invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s (nf_tables)\n", @@ -801,7 +796,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case '0': set_option(&cs->options, OPT_LINENUMBERS, - &args->invflags, cs->invert); + &args->invflags, invert); break; case 'M': @@ -810,7 +805,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'c': set_option(&cs->options, OPT_COUNTERS, &args->invflags, - cs->invert); + invert); args->pcnt = optarg; args->bcnt = strchr(args->pcnt + 1, ','); if (args->bcnt) @@ -853,11 +848,11 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { - if (cs->invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); - cs->invert = true; + invert = true; optarg[0] = '\0'; continue; } @@ -865,12 +860,12 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], exit_tryhelp(2); default: - if (command_default(cs, &xtables_globals) == 1) + if (command_default(cs, &xtables_globals, invert)) /* cf. ip6tables.c */ continue; break; } - cs->invert = false; + invert = false; } if (strcmp(p->table, "nat") == 0 && @@ -896,7 +891,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "unknown arguments found on commandline"); if (!p->command) xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (cs->invert) + if (invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); -- cgit v1.2.3 From 9dc50b5b8e4416219c700331c6e301d840f6e55d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 16 Nov 2020 17:20:57 +0100 Subject: xshared: Merge invflags handling code Join invflags handling between iptables, ip6tables, xtables and arptables. Ebtables still has its own code which differs quite a bit. In order to use a shared set_option() routine, iptables and ip6tables need to provide a local 'invflags' variable which is 16bits wide. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 73 ++++++++++++-------------------------------------- iptables/iptables.c | 72 ++++++++++++------------------------------------- iptables/nft-arp.h | 7 ----- iptables/xshared.c | 43 +++++++++++++++++++++++++++++ iptables/xshared.h | 11 ++++++++ iptables/xtables-arp.c | 44 ------------------------------ iptables/xtables.c | 37 ------------------------- 7 files changed, 88 insertions(+), 199 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 60db11b7..044d9a33 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -96,21 +96,6 @@ struct xtables_globals ip6tables_globals = { .compat_rev = xtables_compatible_revision, }; -static const unsigned int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IP6T_INV_SRCIP, -/* -d */ IP6T_INV_DSTIP, -/* -p */ XT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IP6T_INV_VIA_IN, -/* -o */ IP6T_INV_VIA_OUT, -/*--line*/ 0, -/* -c */ 0, -}; - #define opts ip6tables_globals.opts #define prog_name ip6tables_globals.program_name #define prog_vers ip6tables_globals.program_version @@ -274,28 +259,6 @@ parse_chain(const char *chainname) "Invalid chain name `%s'", chainname); } -static void -set_option(unsigned int *options, unsigned int option, uint8_t *invflg, - int invert) -{ - if (*options & option) - xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - xtables_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - - static void print_header(unsigned int format, const char *chain, struct xtc_handle *handle) { @@ -1083,6 +1046,7 @@ int do_command6(int argc, char *argv[], char **table, struct xtables_target *t; unsigned long long cnt; bool table_set = false; + uint16_t invflags = 0; bool invert = false; /* re-set optind to 0 in case do_command6 gets called @@ -1242,7 +1206,7 @@ int do_command6(int argc, char *argv[], char **table, * Option selection */ case 'p': - set_option(&cs.options, OPT_PROTOCOL, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_PROTOCOL, &invflags, invert); /* Canonicalize into lower case */ @@ -1253,13 +1217,12 @@ int do_command6(int argc, char *argv[], char **table, cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol); cs.fw6.ipv6.flags |= IP6T_F_PROTO; - if (cs.fw6.ipv6.proto == 0 - && (cs.fw6.ipv6.invflags & XT_INV_PROTO)) + if (cs.fw6.ipv6.proto == 0 && (invflags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); if (is_exthdr(cs.fw6.ipv6.proto) - && (cs.fw6.ipv6.invflags & XT_INV_PROTO) == 0) + && (invflags & XT_INV_PROTO) == 0) fprintf(stderr, "Warning: never matched protocol: %s. " "use extension match instead.\n", @@ -1267,29 +1230,26 @@ int do_command6(int argc, char *argv[], char **table, break; case 's': - set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags, - invert); + set_option(&cs.options, OPT_SOURCE, &invflags, invert); shostnetworkmask = optarg; break; case 'd': - set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_DESTINATION, &invflags, invert); dhostnetworkmask = optarg; break; #ifdef IP6T_F_GOTO case 'g': - set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, - invert); + set_option(&cs.options, OPT_JUMP, &invflags, invert); cs.fw6.ipv6.flags |= IP6T_F_GOTO; cs.jumpto = xt_parse_target(optarg); break; #endif case 'j': - set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, - invert); + set_option(&cs.options, OPT_JUMP, &invflags, invert); command_jump(&cs, optarg); break; @@ -1299,7 +1259,7 @@ int do_command6(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_VIANAMEIN, &invflags, invert); xtables_parse_interface(optarg, cs.fw6.ipv6.iniface, @@ -1311,7 +1271,7 @@ int do_command6(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_VIANAMEOUT, &invflags, invert); xtables_parse_interface(optarg, cs.fw6.ipv6.outiface, @@ -1321,7 +1281,7 @@ int do_command6(int argc, char *argv[], char **table, case 'v': if (!verbose) set_option(&cs.options, OPT_VERBOSE, - &cs.fw6.ipv6.invflags, invert); + &invflags, invert); verbose++; break; @@ -1349,8 +1309,7 @@ int do_command6(int argc, char *argv[], char **table, break; case 'n': - set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags, - invert); + set_option(&cs.options, OPT_NUMERIC, &invflags, invert); break; case 't': @@ -1366,7 +1325,7 @@ int do_command6(int argc, char *argv[], char **table, break; case 'x': - set_option(&cs.options, OPT_EXPANDED, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_EXPANDED, &invflags, invert); break; @@ -1379,7 +1338,7 @@ int do_command6(int argc, char *argv[], char **table, exit(0); case '0': - set_option(&cs.options, OPT_LINENUMBERS, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_LINENUMBERS, &invflags, invert); break; @@ -1389,7 +1348,7 @@ int do_command6(int argc, char *argv[], char **table, case 'c': - set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags, + set_option(&cs.options, OPT_COUNTERS, &invflags, invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); @@ -1479,6 +1438,8 @@ int do_command6(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); + cs.fw6.ipv6.invflags = invflags; + if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { if (!(cs.options & OPT_DESTINATION)) dhostnetworkmask = "::0/0"; diff --git a/iptables/iptables.c b/iptables/iptables.c index 09760173..da67dd2e 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -94,22 +94,6 @@ struct xtables_globals iptables_globals = { .compat_rev = xtables_compatible_revision, }; -static const int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ XT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/*--line*/ 0, -/* -c */ 0, -/* -f */ IPT_INV_FRAG, -}; - #define opts iptables_globals.opts #define prog_name iptables_globals.program_name #define prog_vers iptables_globals.program_version @@ -265,27 +249,6 @@ parse_chain(const char *chainname) "Invalid chain name `%s'", chainname); } -static void -set_option(unsigned int *options, unsigned int option, uint8_t *invflg, - int invert) -{ - if (*options & option) - xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - xtables_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - static void print_header(unsigned int format, const char *chain, struct xtc_handle *handle) { @@ -1078,6 +1041,7 @@ int do_command4(int argc, char *argv[], char **table, struct xtables_target *t; unsigned long long cnt; bool table_set = false; + uint16_t invflags = 0; bool invert = false; /* re-set optind to 0 in case do_command4 gets called @@ -1236,7 +1200,7 @@ int do_command4(int argc, char *argv[], char **table, * Option selection */ case 'p': - set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_PROTOCOL, &invflags, invert); /* Canonicalize into lower case */ @@ -1246,36 +1210,32 @@ int do_command4(int argc, char *argv[], char **table, cs.protocol = optarg; cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); - if (cs.fw.ip.proto == 0 - && (cs.fw.ip.invflags & XT_INV_PROTO)) + if (cs.fw.ip.proto == 0 && (invflags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); break; case 's': - set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, - invert); + set_option(&cs.options, OPT_SOURCE, &invflags, invert); shostnetworkmask = optarg; break; case 'd': - set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_DESTINATION, &invflags, invert); dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO case 'g': - set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, - invert); + set_option(&cs.options, OPT_JUMP, &invflags, invert); cs.fw.ip.flags |= IPT_F_GOTO; cs.jumpto = xt_parse_target(optarg); break; #endif case 'j': - set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, - invert); + set_option(&cs.options, OPT_JUMP, &invflags, invert); command_jump(&cs, optarg); break; @@ -1285,7 +1245,7 @@ int do_command4(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_VIANAMEIN, &invflags, invert); xtables_parse_interface(optarg, cs.fw.ip.iniface, @@ -1297,7 +1257,7 @@ int do_command4(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_VIANAMEOUT, &invflags, invert); xtables_parse_interface(optarg, cs.fw.ip.outiface, @@ -1305,7 +1265,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'f': - set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_FRAGMENT, &invflags, invert); cs.fw.ip.flags |= IPT_F_FRAG; break; @@ -1313,7 +1273,7 @@ int do_command4(int argc, char *argv[], char **table, case 'v': if (!verbose) set_option(&cs.options, OPT_VERBOSE, - &cs.fw.ip.invflags, invert); + &invflags, invert); verbose++; break; @@ -1341,7 +1301,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'n': - set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_NUMERIC, &invflags, invert); break; @@ -1358,7 +1318,7 @@ int do_command4(int argc, char *argv[], char **table, break; case 'x': - set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_EXPANDED, &invflags, invert); break; @@ -1371,7 +1331,7 @@ int do_command4(int argc, char *argv[], char **table, exit(0); case '0': - set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_LINENUMBERS, &invflags, invert); break; @@ -1381,7 +1341,7 @@ int do_command4(int argc, char *argv[], char **table, case 'c': - set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags, + set_option(&cs.options, OPT_COUNTERS, &invflags, invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); @@ -1467,6 +1427,8 @@ int do_command4(int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); + cs.fw.ip.invflags = invflags; + if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { if (!(cs.options & OPT_DESTINATION)) dhostnetworkmask = "0.0.0.0/0"; diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h index 0d93a31f..3411fc3d 100644 --- a/iptables/nft-arp.h +++ b/iptables/nft-arp.h @@ -4,11 +4,4 @@ extern char *arp_opcodes[]; #define NUMOPCODES 9 -/* define invflags which won't collide with IPT ones */ -#define IPT_INV_SRCDEVADDR 0x0080 -#define IPT_INV_TGTDEVADDR 0x0100 -#define IPT_INV_ARPHLN 0x0200 -#define IPT_INV_ARPOP 0x0400 -#define IPT_INV_ARPHRD 0x0800 - #endif diff --git a/iptables/xshared.c b/iptables/xshared.c index afd7a9d6..a3f473ea 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -853,3 +853,46 @@ char opt2char(int option) return *ptr; } + +static const int inverse_for_options[NUMBER_OF_OPT] = +{ +/* -n */ 0, +/* -s */ IPT_INV_SRCIP, +/* -d */ IPT_INV_DSTIP, +/* -p */ XT_INV_PROTO, +/* -j */ 0, +/* -v */ 0, +/* -x */ 0, +/* -i */ IPT_INV_VIA_IN, +/* -o */ IPT_INV_VIA_OUT, +/*--line*/ 0, +/* -c */ 0, +/* -f */ IPT_INV_FRAG, +/* 2 */ IPT_INV_SRCDEVADDR, +/* 3 */ IPT_INV_TGTDEVADDR, +/* -l */ IPT_INV_ARPHLN, +/* 4 */ IPT_INV_ARPOP, +/* 5 */ IPT_INV_ARPHRD, +/* 6 */ IPT_INV_PROTO, +}; + +void +set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, + bool invert) +{ + if (*options & option) + xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", + opt2char(option)); + *options |= option; + + if (invert) { + unsigned int i; + for (i = 0; 1 << i != option; i++); + + if (!inverse_for_options[i]) + xtables_error(PARAMETER_PROBLEM, + "cannot have ! before -%c", + opt2char(option)); + *invflg |= inverse_for_options[i]; + } +} diff --git a/iptables/xshared.h b/iptables/xshared.h index af2a5adb..dace221b 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -68,6 +68,17 @@ struct xtables_globals; struct xtables_rule_match; struct xtables_target; +/* define invflags which won't collide with IPT ones */ +#define IPT_INV_SRCDEVADDR 0x0080 +#define IPT_INV_TGTDEVADDR 0x0100 +#define IPT_INV_ARPHLN 0x0200 +#define IPT_INV_ARPOP 0x0400 +#define IPT_INV_ARPHRD 0x0800 + +void +set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, + bool invert); + /** * xtables_afinfo - protocol family dependent information * @kmod: kernel module basename (e.g. "ip_tables") diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 4a89ae95..4a351f0c 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -105,29 +105,6 @@ struct xtables_globals arptables_globals = { .compat_rev = nft_compatible_revision, }; -/* index relates to bit of each OPT_* value */ -static int inverse_for_options[] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ 0, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/*--line*/ 0, -/* -c */ 0, -/* -f */ 0, -/* 2 */ IPT_INV_SRCDEVADDR, -/* 3 */ IPT_INV_TGTDEVADDR, -/* -l */ IPT_INV_ARPHLN, -/* 4 */ IPT_INV_ARPOP, -/* 5 */ IPT_INV_ARPHRD, -/* 6 */ IPT_INV_PROTO, -}; - /***********************************************/ /* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */ /***********************************************/ @@ -298,27 +275,6 @@ check_inverse(const char option[], int *invert, int *optidx, int argc) return false; } -static void -set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, - int invert) -{ - if (*options & option) - xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - xtables_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - static int list_entries(struct nft_handle *h, const char *chain, const char *table, int rulenum, int verbose, int numeric, int expanded, diff --git a/iptables/xtables.c b/iptables/xtables.c index 73531ca8..daa9b137 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -94,22 +94,6 @@ struct xtables_globals xtables_globals = { .compat_rev = nft_compatible_revision, }; -static const int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ XT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/*--line*/ 0, -/* -c */ 0, -/* -f */ IPT_INV_FRAG, -}; - #define opts xt_params->opts #define prog_name xt_params->program_name #define prog_vers xt_params->program_version @@ -238,27 +222,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static void -set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, - bool invert) -{ - if (*options & option) - xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - xtables_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - static int add_entry(const char *chain, const char *table, -- cgit v1.2.3 From eea68ca828b6a757490d91fc87dcac2f15647f40 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 20 Jun 2020 10:11:52 +0200 Subject: ebtables-translate: Use shared ebt_get_current_chain() function Drop the local reimplementation. It was barely different enough to be buggy: | % ebtables-nft -A foo -o eth0 -j ACCEPT | % xtables-nft-multi ebtables-translate -A foo -o eth0 -j ACCEPT | ebtables-translate v1.8.5 (nf_tables): Use -o only in OUTPUT, FORWARD and POSTROUTING chains | Try `ebtables-translate -h' or 'ebtables-translate --help' for more information. With this change, output is as expected: | % xtables-nft-multi ebtables-translate -A foo -o eth0 -j ACCEPT | nft add rule bridge filter foo oifname "eth0" counter accept This is roughly the same issue fixed in commit e1ccd979e6849 ("ebtables: fix over-eager -o checks on custom chains"). Signed-off-by: Phil Sutter --- iptables/xtables-eb-translate.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 04b3dfa0..0539a829 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -64,22 +64,6 @@ static int parse_rule_number(const char *rule) return rule_nr; } -static int get_current_chain(const char *chain) -{ - if (strcmp(chain, "PREROUTING") == 0) - return NF_BR_PRE_ROUTING; - else if (strcmp(chain, "INPUT") == 0) - return NF_BR_LOCAL_IN; - else if (strcmp(chain, "FORWARD") == 0) - return NF_BR_FORWARD; - else if (strcmp(chain, "OUTPUT") == 0) - return NF_BR_LOCAL_OUT; - else if (strcmp(chain, "POSTROUTING") == 0) - return NF_BR_POST_ROUTING; - - return -1; -} - /* * The original ebtables parser */ @@ -240,7 +224,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char "Multiple commands are not allowed"); command = c; chain = optarg; - selected_chain = get_current_chain(chain); + selected_chain = ebt_get_current_chain(chain); p.chain = chain; flags |= OPT_COMMAND; -- cgit v1.2.3 From 556f704458cdb509d395ddb7d2629987d60e762e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 17 Nov 2020 00:57:10 +0100 Subject: Use proto_to_name() from xshared in more places Share the common proto name lookup code. While being at it, make proto number variable 16bit, values may exceed 256. This aligns iptables-nft '-p' argument printing with legacy iptables. In practice, this should make a difference only in corner cases. Signed-off-by: Phil Sutter --- include/xtables.h | 2 +- iptables/ip6tables.c | 22 +++++----------------- iptables/iptables.c | 20 +++++--------------- iptables/nft-shared.c | 6 +++--- iptables/xshared.c | 2 +- iptables/xshared.h | 2 +- 6 files changed, 16 insertions(+), 38 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index df1eaee3..1fd5f63a 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -395,7 +395,7 @@ struct xtables_rule_match { */ struct xtables_pprot { const char *name; - uint8_t num; + uint16_t num; }; enum xtables_tryload { diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 044d9a33..e967c040 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -759,28 +759,16 @@ print_iface(char letter, const char *iface, const unsigned char *mask, } } -/* The ip6tables looks up the /etc/protocols. */ static void print_proto(uint16_t proto, int invert) { if (proto) { - unsigned int i; + const char *pname = proto_to_name(proto, 0); const char *invertstr = invert ? " !" : ""; - const struct protoent *pent = getprotobynumber(proto); - if (pent) { - printf("%s -p %s", - invertstr, pent->p_name); - return; - } - - for (i = 0; xtables_chain_protos[i].name != NULL; ++i) - if (xtables_chain_protos[i].num == proto) { - printf("%s -p %s", - invertstr, xtables_chain_protos[i].name); - return; - } - - printf("%s -p %u", invertstr, proto); + if (pname) + printf("%s -p %s", invertstr, pname); + else + printf("%s -p %u", invertstr, proto); } } diff --git a/iptables/iptables.c b/iptables/iptables.c index da67dd2e..b925f089 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -727,23 +727,13 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, static void print_proto(uint16_t proto, int invert) { if (proto) { - unsigned int i; + const char *pname = proto_to_name(proto, 0); const char *invertstr = invert ? " !" : ""; - const struct protoent *pent = getprotobynumber(proto); - if (pent) { - printf("%s -p %s", invertstr, pent->p_name); - return; - } - - for (i = 0; xtables_chain_protos[i].name != NULL; ++i) - if (xtables_chain_protos[i].num == proto) { - printf("%s -p %s", - invertstr, xtables_chain_protos[i].name); - return; - } - - printf("%s -p %u", invertstr, proto); + if (pname) + printf("%s -p %s", invertstr, pname); + else + printf("%s -p %u", invertstr, proto); } } diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index c1664b50..4253b081 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -826,13 +826,13 @@ void save_rule_details(const struct iptables_command_state *cs, } if (proto > 0) { - const struct protoent *pent = getprotobynumber(proto); + const char *pname = proto_to_name(proto, 0); if (invflags & XT_INV_PROTO) printf("! "); - if (pent) - printf("-p %s ", pent->p_name); + if (pname) + printf("-p %s ", pname); else printf("-p %u ", proto); } diff --git a/iptables/xshared.c b/iptables/xshared.c index a3f473ea..49a88de5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -48,7 +48,7 @@ void print_extension_helps(const struct xtables_target *t, } const char * -proto_to_name(uint8_t proto, int nolookup) +proto_to_name(uint16_t proto, int nolookup) { unsigned int i; diff --git a/iptables/xshared.h b/iptables/xshared.h index dace221b..823894f9 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -162,7 +162,7 @@ enum { extern void print_extension_helps(const struct xtables_target *, const struct xtables_rule_match *); -extern const char *proto_to_name(uint8_t, int); +extern const char *proto_to_name(uint16_t, int); extern int command_default(struct iptables_command_state *, struct xtables_globals *, bool invert); extern struct xtables_match *load_proto(struct iptables_command_state *); -- cgit v1.2.3 From a61282ec6a1697bfb40f19d13a28a74559050167 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 4 May 2021 16:03:24 +0200 Subject: extensions: sctp: Fix nftables translation If both sport and dport was present, incorrect nft syntax was generated. Fixes: defc7bd2bac89 ("extensions: libxt_sctp: Add translation to nft") Signed-off-by: Phil Sutter --- extensions/libxt_sctp.c | 10 ++++------ extensions/libxt_sctp.txlate | 10 +++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index 140de265..ee4e99eb 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -495,15 +495,13 @@ static int sctp_xlate(struct xt_xlate *xl, if (!einfo->flags) return 0; - xt_xlate_add(xl, "sctp "); - if (einfo->flags & XT_SCTP_SRC_PORTS) { if (einfo->spts[0] != einfo->spts[1]) - xt_xlate_add(xl, "sport%s %u-%u", + xt_xlate_add(xl, "sctp sport%s %u-%u", einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "", einfo->spts[0], einfo->spts[1]); else - xt_xlate_add(xl, "sport%s %u", + xt_xlate_add(xl, "sctp sport%s %u", einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "", einfo->spts[0]); space = " "; @@ -511,11 +509,11 @@ static int sctp_xlate(struct xt_xlate *xl, if (einfo->flags & XT_SCTP_DEST_PORTS) { if (einfo->dpts[0] != einfo->dpts[1]) - xt_xlate_add(xl, "%sdport%s %u-%u", space, + xt_xlate_add(xl, "%ssctp dport%s %u-%u", space, einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0], einfo->dpts[1]); else - xt_xlate_add(xl, "%sdport%s %u", space, + xt_xlate_add(xl, "%ssctp dport%s %u", space, einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); } diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate index 72f4641a..0d6c59e1 100644 --- a/extensions/libxt_sctp.txlate +++ b/extensions/libxt_sctp.txlate @@ -23,16 +23,16 @@ iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT nft add rule ip filter INPUT sctp dport != 50-56 counter accept iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 dport 80 counter accept +nft add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 dport 80-100 counter accept +nft add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50-55 dport 80 counter accept +nft add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 dport != 80-100 counter accept +nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport != 50-55 dport 80 counter accept +nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept -- cgit v1.2.3 From 5818be177110a09120dd8fe4bd2533acbf8da301 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 4 May 2021 16:26:42 +0200 Subject: extensions: sctp: Translate --chunk-types option The translation is not fully complete as it is not possible to map 'any' match type into nft syntax with a single rule. Also, 'only' match type translation is a bit poor as it explicitly lists all chunk types that are supposed to be missing. Signed-off-by: Phil Sutter --- extensions/libxt_sctp.c | 91 +++++++++++++++++++++++++++++++++++--------- extensions/libxt_sctp.txlate | 6 +++ 2 files changed, 78 insertions(+), 19 deletions(-) diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index ee4e99eb..5d8ab85c 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -92,28 +92,29 @@ struct sctp_chunk_names { const char *name; unsigned int chunk_type; const char *valid_flags; + const char *nftname; }; /*'ALL' and 'NONE' will be treated specially. */ static const struct sctp_chunk_names sctp_chunk_names[] -= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE"}, - { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"}, - { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"}, - { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"}, - { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"}, - { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"}, - { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"}, - { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"}, - { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"}, - { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"}, - { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"}, - { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"}, - { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"}, - { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"}, - { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"}, - { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------"}, - { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------"}, - { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------"}, += { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE", .nftname = "data" }, + { .name = "INIT", .chunk_type = 1, .valid_flags = "--------", .nftname = "init" }, + { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------", .nftname = "init-ack" }, + { .name = "SACK", .chunk_type = 3, .valid_flags = "--------", .nftname = "sack" }, + { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------", .nftname = "heartbeat" }, + { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------", .nftname = "heartbeat-ack" }, + { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T", .nftname = "abort" }, + { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------", .nftname = "shutdown" }, + { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------", .nftname = "shutdown-ack" }, + { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------", .nftname = "error" }, + { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------", .nftname = "cookie-echo" }, + { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------", .nftname = "cookie-ack" }, + { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" }, + { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" }, + { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" }, + { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" }, + { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" }, + { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" }, }; static void @@ -485,12 +486,52 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match) } } +static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space, + const struct xt_sctp_info *einfo, + const struct sctp_chunk_names *scn) +{ + bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES; + const struct xt_sctp_flag_info *flag_info = NULL; + int i; + + if (!scn->nftname) + return space; + + if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) { + if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY) + return space; + + xt_xlate_add(xl, "%ssctp chunk %s %s", space, + scn->nftname, inv ? "exists" : "missing"); + return " "; + } + + for (i = 0; i < einfo->flag_count; i++) { + if (einfo->flag_info[i].chunktype == scn->chunk_type) { + flag_info = &einfo->flag_info[i]; + break; + } + } + + if (!flag_info) { + xt_xlate_add(xl, "%ssctp chunk %s %s", space, + scn->nftname, inv ? "missing" : "exists"); + return " "; + } + + xt_xlate_add(xl, "%ssctp chunk %s flags & 0x%x %s 0x%x", space, + scn->nftname, flag_info->flag_mask, + inv ? "!=" : "==", flag_info->flag); + + return " "; +} + static int sctp_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { const struct xt_sctp_info *einfo = (const struct xt_sctp_info *)params->match->data; - char *space = ""; + const char *space = ""; if (!einfo->flags) return 0; @@ -516,6 +557,18 @@ static int sctp_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "%ssctp dport%s %u", space, einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); + space = " "; + } + + if (einfo->flags & XT_SCTP_CHUNK_TYPES) { + int i; + + if (einfo->chunk_match_type == SCTP_CHUNK_MATCH_ANY) + return 0; + + for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++) + space = sctp_xlate_chunk(xl, space, einfo, + &sctp_chunk_names[i]); } return 1; diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate index 0d6c59e1..bb817525 100644 --- a/extensions/libxt_sctp.txlate +++ b/extensions/libxt_sctp.txlate @@ -36,3 +36,9 @@ nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept + +iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT +nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept + +iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT +nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing counter accept -- cgit v1.2.3 From 97fabae738a74bd04a7793e1199cd2b8a69122bc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 13 Nov 2020 21:04:39 +0100 Subject: libxtables: Drop leftover variable in xtables_numeric_to_ip6addr() Variable 'err' was only used in removed debug code, so drop it as well. Fixes: 7f526c9373c17 ("libxtables: xtables: remove unnecessary debug code") Signed-off-by: Phil Sutter --- libxtables/xtables.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index e6edfb5b..82815cae 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -1808,9 +1808,8 @@ const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp) struct in6_addr *xtables_numeric_to_ip6addr(const char *num) { static struct in6_addr ap; - int err; - if ((err = inet_pton(AF_INET6, num, &ap)) == 1) + if (inet_pton(AF_INET6, num, &ap) == 1) return ≈ return NULL; -- cgit v1.2.3 From 8bb5bcae57c83066c224efa5fd29ed4822a766fc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 13 Nov 2020 21:13:50 +0100 Subject: extensions: libebt_ip6: Drop unused variables They are being assigned to but never read. Fixes: 5c8ce9c6aede0 ("ebtables-compat: add 'ip6' match extension") Signed-off-by: Phil Sutter --- extensions/libebt_ip6.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index b8a5a5d8..301bed9a 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -250,9 +250,8 @@ static void brip6_init(struct xt_entry_match *match) static struct in6_addr *numeric_to_addr(const char *num) { static struct in6_addr ap; - int err; - if ((err=inet_pton(AF_INET6, num, &ap)) == 1) + if (inet_pton(AF_INET6, num, &ap) == 1) return ≈ return (struct in6_addr *)NULL; } @@ -292,7 +291,6 @@ static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct i char buf[256]; char *p; int i; - int err; strncpy(buf, address, sizeof(buf) - 1); /* first the mask */ @@ -309,7 +307,7 @@ static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct i if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) strcpy(buf, "::"); - if ((err=inet_pton(AF_INET6, buf, addr)) < 1) { + if (inet_pton(AF_INET6, buf, addr) < 1) { xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf); return; } -- cgit v1.2.3 From ffe88f8f01263687e82ef4d3d2bdc0cb5444711e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 11:04:30 +0200 Subject: libxtables: Fix memleak in xtopt_parse_hostmask() The allocated hostmask duplicate needs to be freed again. Fixes: 66266abd17adc ("libxtables: XTTYPE_HOSTMASK support") Signed-off-by: Phil Sutter --- libxtables/xtoptions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c index d329f2ff..0dcdf607 100644 --- a/libxtables/xtoptions.c +++ b/libxtables/xtoptions.c @@ -763,6 +763,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb) cb->arg = p; xtopt_parse_plenmask(cb); cb->arg = orig_arg; + free(work); } static void xtopt_parse_ethermac(struct xt_option_call *cb) -- cgit v1.2.3 From eab75ed36a4f204ddab0c40ba42c5a300634d5c3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 11:55:20 +0200 Subject: nft: Avoid memleak in error path of nft_cmd_new() If rule allocation fails, free the allocated 'cmd' before returning to caller. Fixes: a7f1e208cdf9c ("nft: split parsing from netlink commands") Signed-off-by: Phil Sutter --- iptables/nft-cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index f2b935c5..c3f6c14e 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -35,8 +35,10 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, if (state) { rule = nft_rule_new(h, chain, table, state); - if (!rule) + if (!rule) { + nft_cmd_free(cmd); return NULL; + } cmd->obj.rule = rule; -- cgit v1.2.3 From 0729ab37c5d90b78dd3bc8c9addb8a1c60708eff Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 11:58:06 +0200 Subject: nft: Avoid buffer size warnings copying iface names The call to strncpy() is actually not needed: source buffer is only IFNAMSIZ bytes large and guaranteed to be null-terminated. Use this to avoid compiler warnings due to size parameter matching the destination buffer size by performing the copy using (dumb) memcpy() instead. Signed-off-by: Phil Sutter --- iptables/nft-ipv4.c | 4 ++-- iptables/nft-ipv6.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index a5b835b1..34f94bd8 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -348,11 +348,11 @@ static void nft_ipv4_post_parse(int command, */ cs->fw.ip.invflags = args->invflags; - strncpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ); memcpy(cs->fw.ip.iniface_mask, args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); - strncpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ); memcpy(cs->fw.ip.outiface_mask, args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 46008fc5..d9c9400a 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -293,11 +293,11 @@ static void nft_ipv6_post_parse(int command, struct iptables_command_state *cs, */ cs->fw6.ipv6.invflags = args->invflags; - strncpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ); memcpy(cs->fw6.ipv6.iniface_mask, args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); - strncpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ); memcpy(cs->fw6.ipv6.outiface_mask, args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); -- cgit v1.2.3 From 084671d5acaaf749648e828c2ed3b319de651764 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 12:50:57 +0200 Subject: iptables-apply: Drop unused variable It was assigned to but never read. Fixes: b45b4e3903414 ("iptables-apply: script and manpage update") Signed-off-by: Phil Sutter --- iptables/iptables-apply | 1 - 1 file changed, 1 deletion(-) diff --git a/iptables/iptables-apply b/iptables/iptables-apply index 4683b1b4..3a7df5e3 100755 --- a/iptables/iptables-apply +++ b/iptables/iptables-apply @@ -231,7 +231,6 @@ case "$MODE" in "$RUNCMD" & CMD_PID=$! ( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) & - CMDTIMEOUT_PID=$! if ! wait "$CMD_PID"; then echo "failed." echo "Error: unknown error running command: $RUNCMD" >&2 -- cgit v1.2.3 From ca840c20b7b754d36a1abe7e597fd730dea142d4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 14:04:43 +0200 Subject: extensions: libebt_ip6: Use xtables_ip6parse_any() The code was almost identical and suffered from the same problem as fixed in commit a76a5c997a235 ("libxtables: fix two off-by-one memory corruption bugs"). The only functional change this involves is ebt_parse_ip6_address() will now accept hostnames as well. Signed-off-by: Phil Sutter --- extensions/libebt_ip6.c | 74 +++++++------------------------------------------ 1 file changed, 10 insertions(+), 64 deletions(-) diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index 301bed9a..3cc39271 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -247,73 +247,19 @@ static void brip6_init(struct xt_entry_match *match) memset(ipinfo->dmsk.s6_addr, 0, sizeof(ipinfo->dmsk.s6_addr)); } -static struct in6_addr *numeric_to_addr(const char *num) +/* wrap xtables_ip6parse_any(), ignoring any but the first returned address */ +static void ebt_parse_ip6_address(char *address, + struct in6_addr *addr, struct in6_addr *msk) { - static struct in6_addr ap; - - if (inet_pton(AF_INET6, num, &ap) == 1) - return ≈ - return (struct in6_addr *)NULL; -} - -static struct in6_addr *parse_ip6_mask(char *mask) -{ - static struct in6_addr maskaddr; struct in6_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 128 bits */ - memset(&maskaddr, 0xff, sizeof maskaddr); - return &maskaddr; - } - if ((addrp = numeric_to_addr(mask)) != NULL) - return addrp; - if (!xtables_strtoui(mask, NULL, &bits, 0, 128)) - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Mask '%s' specified", mask); - if (bits != 0) { - char *p = (char *)&maskaddr; - memset(p, 0xff, bits / 8); - memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); - p[bits / 8] = 0xff << (8 - (bits & 7)); - return &maskaddr; - } + unsigned int naddrs; - memset(&maskaddr, 0, sizeof maskaddr); - return &maskaddr; -} - -/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0]. - * The string pointed to by address can be altered. */ -static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct in6_addr *msk) -{ - struct in6_addr *tmp_addr; - char buf[256]; - char *p; - int i; - - strncpy(buf, address, sizeof(buf) - 1); - /* first the mask */ - buf[sizeof(buf) - 1] = '\0'; - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - tmp_addr = parse_ip6_mask(p + 1); - } else - tmp_addr = parse_ip6_mask(NULL); - - *msk = *tmp_addr; - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) - strcpy(buf, "::"); - - if (inet_pton(AF_INET6, buf, addr) < 1) { - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf); - return; - } - - for (i = 0; i < 4; i++) - addr->s6_addr32[i] &= msk->s6_addr32[i]; + xtables_ip6parse_any(address, &addrp, msk, &naddrs); + if (naddrs != 1) + xtables_error(PARAMETER_PROBLEM, + "Invalid IPv6 Address '%s' specified", address); + memcpy(addr, addrp, sizeof(*addr)); + free(addrp); } #define OPT_SOURCE 0x01 -- cgit v1.2.3 From 9b85e1ab3dbf0d9344562c5c76114496e3ebaa3a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 12:56:06 +0200 Subject: libxtables: Introduce xtables_strdup() and use it everywhere This wraps strdup(), checking for errors. Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 3 ++- extensions/libebt_ip6.c | 2 +- extensions/libebt_stp.c | 3 ++- extensions/libip6t_DNAT.c | 4 +--- extensions/libip6t_SNAT.c | 4 +--- extensions/libip6t_dst.c | 8 +++----- extensions/libip6t_hbh.c | 7 +++---- extensions/libip6t_ipv6header.c | 2 +- extensions/libip6t_mh.c | 2 +- extensions/libip6t_rt.c | 7 +++---- extensions/libipt_DNAT.c | 8 ++------ extensions/libipt_SNAT.c | 4 +--- extensions/libxt_dccp.c | 2 +- extensions/libxt_hashlimit.c | 5 +---- extensions/libxt_iprange.c | 4 +--- extensions/libxt_multiport.c | 6 ++---- extensions/libxt_sctp.c | 4 ++-- extensions/libxt_set.h | 4 ++-- extensions/libxt_tcp.c | 4 ++-- include/xtables.h | 1 + iptables/iptables-xml.c | 4 ++-- iptables/nft-cache.c | 4 ++-- iptables/nft-cmd.c | 13 +++++++------ iptables/xshared.c | 2 +- libxtables/xtables.c | 12 ++++++++++++ libxtables/xtoptions.c | 14 +++----------- 26 files changed, 60 insertions(+), 73 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index acb9bfcd..51649ffb 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -175,7 +175,8 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) char *buffer; char *cp; - buffer = strdup(portstring); + buffer = xtables_strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) ports[0] = ports[1] = xtables_parse_port(buffer, NULL); else { diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index 3cc39271..a686a285 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -93,7 +93,7 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) char *buffer; char *cp; - buffer = strdup(portstring); + buffer = xtables_strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) ports[0] = ports[1] = xtables_parse_port(buffer, NULL); else { diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c index 81ba572c..3e9e2447 100644 --- a/extensions/libebt_stp.c +++ b/extensions/libebt_stp.c @@ -90,7 +90,8 @@ static int parse_range(const char *portstring, void *lower, void *upper, uint32_t low_nr, upp_nr; int ret = 0; - buffer = strdup(portstring); + buffer = xtables_strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) { low_nr = strtoul(buffer, &end, 10); if (*end || low_nr < min || low_nr > max) { diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c index 89c5ceb1..f1ad8143 100644 --- a/extensions/libip6t_DNAT.c +++ b/extensions/libip6t_DNAT.c @@ -58,9 +58,7 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev) char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; const struct in6_addr *ip; - arg = strdup(orig_arg); - if (arg == NULL) - xtables_error(RESOURCE_PROBLEM, "strdup"); + arg = xtables_strdup(orig_arg); start = strchr(arg, '['); if (start == NULL) { diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c index 7d74b3d7..6d19614c 100644 --- a/extensions/libip6t_SNAT.c +++ b/extensions/libip6t_SNAT.c @@ -52,9 +52,7 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; const struct in6_addr *ip; - arg = strdup(orig_arg); - if (arg == NULL) - xtables_error(RESOURCE_PROBLEM, "strdup"); + arg = xtables_strdup(orig_arg); start = strchr(arg, '['); if (start == NULL) { diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c index fe7e3403..bf0e3e43 100644 --- a/extensions/libip6t_dst.c +++ b/extensions/libip6t_dst.c @@ -57,11 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts) { char *buffer, *cp, *next, *range; unsigned int i; - - buffer = strdup(optsstr); - if (!buffer) - xtables_error(OTHER_PROBLEM, "strdup failed"); - + + buffer = xtables_strdup(optsstr); + for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++) { next = strchr(cp, ','); diff --git a/extensions/libip6t_hbh.c b/extensions/libip6t_hbh.c index 4cebecfd..74e87cda 100644 --- a/extensions/libip6t_hbh.c +++ b/extensions/libip6t_hbh.c @@ -57,10 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts) { char *buffer, *cp, *next, *range; unsigned int i; - - buffer = strdup(optsstr); - if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed"); - + + buffer = xtables_strdup(optsstr); + for (cp=buffer, i=0; cp && ipflags[i] = 0; diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index 5d8ab85c..a4c5415f 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -69,7 +69,7 @@ parse_sctp_ports(const char *portstring, char *buffer; char *cp; - buffer = strdup(portstring); + buffer = xtables_strdup(portstring); DEBUGP("%s\n", portstring); if ((cp = strchr(buffer, ':')) == NULL) { ports[0] = ports[1] = xtables_parse_port(buffer, "sctp"); @@ -164,7 +164,7 @@ parse_sctp_chunk(struct xt_sctp_info *einfo, int found = 0; char *chunk_flags; - buffer = strdup(chunks); + buffer = xtables_strdup(chunks); DEBUGP("Buffer: %s\n", buffer); SCTP_CHUNKMAP_RESET(einfo->chunkmap); diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index 41dfbd30..ad895a75 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -141,7 +141,7 @@ get_set_byname(const char *setname, struct xt_set_info *info) static void parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) { - char *saved = strdup(opt_arg); + char *saved = xtables_strdup(opt_arg); char *ptr, *tmp = saved; int i = 0; @@ -167,7 +167,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) static void parse_dirs(const char *opt_arg, struct xt_set_info *info) { - char *saved = strdup(opt_arg); + char *saved = xtables_strdup(opt_arg); char *ptr, *tmp = saved; while (info->dim < IPSET_DIM_MAX && tmp != NULL) { diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 58f3c0a0..383e4db5 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -43,7 +43,7 @@ parse_tcp_ports(const char *portstring, uint16_t *ports) char *buffer; char *cp; - buffer = strdup(portstring); + buffer = xtables_strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) ports[0] = ports[1] = xtables_parse_port(buffer, "tcp"); else { @@ -83,7 +83,7 @@ parse_tcp_flag(const char *flags) char *ptr; char *buffer; - buffer = strdup(flags); + buffer = xtables_strdup(flags); for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { unsigned int i; diff --git a/include/xtables.h b/include/xtables.h index 1fd5f63a..5b13f348 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -453,6 +453,7 @@ extern void xtables_set_nfproto(uint8_t); extern void *xtables_calloc(size_t, size_t); extern void *xtables_malloc(size_t); extern void *xtables_realloc(void *, size_t); +char *xtables_strdup(const char *); extern int xtables_insmod(const char *, const char *, bool); extern int xtables_load_ko(const char *, bool); diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c index 98d03dda..6cf059fb 100644 --- a/iptables/iptables-xml.c +++ b/iptables/iptables-xml.c @@ -213,8 +213,8 @@ saveChain(char *chain, char *policy, struct xt_counters *ctr) "%s: line %u chain name invalid\n", prog_name, line); - chains[nextChain].chain = strdup(chain); - chains[nextChain].policy = strdup(policy); + chains[nextChain].chain = xtables_strdup(chain); + chains[nextChain].policy = xtables_strdup(policy); chains[nextChain].count = *ctr; chains[nextChain].created = 0; nextChain++; diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 8fbf9727..2c88301c 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -40,7 +40,7 @@ static void cache_chain_list_insert(struct list_head *list, const char *name) } new = xtables_malloc(sizeof(*new)); - new->name = strdup(name); + new->name = xtables_strdup(name); list_add_tail(&new->head, pos ? &pos->head : list); } @@ -56,7 +56,7 @@ void nft_cache_level_set(struct nft_handle *h, int level, return; if (!req->table) - req->table = strdup(cmd->table); + req->table = xtables_strdup(cmd->table); else assert(!strcmp(req->table, cmd->table)); diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index c3f6c14e..a0c76a79 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -11,6 +11,7 @@ #include #include +#include #include "nft.h" #include "nft-cmd.h" @@ -27,9 +28,9 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, return NULL; cmd->command = command; - cmd->table = strdup(table); + cmd->table = xtables_strdup(table); if (chain) - cmd->chain = strdup(chain); + cmd->chain = xtables_strdup(chain); cmd->rulenum = rulenum; cmd->verbose = verbose; @@ -43,7 +44,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, cmd->obj.rule = rule; if (!state->target && strlen(state->jumpto) > 0) - cmd->jumpto = strdup(state->jumpto); + cmd->jumpto = xtables_strdup(state->jumpto); } list_add_tail(&cmd->head, &h->cmd_list); @@ -238,7 +239,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain, if (!cmd) return 0; - cmd->rename = strdup(newname); + cmd->rename = xtables_strdup(newname); nft_cache_level_set(h, NFT_CL_CHAINS, cmd); @@ -304,7 +305,7 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table, if (!cmd) return 0; - cmd->policy = strdup(policy); + cmd->policy = xtables_strdup(policy); if (counters) cmd->counters = *counters; @@ -389,7 +390,7 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table, if (!cmd) return 0; - cmd->policy = strdup(policy); + cmd->policy = xtables_strdup(policy); nft_cache_level_set(h, NFT_CL_RULES, cmd); diff --git a/iptables/xshared.c b/iptables/xshared.c index 49a88de5..ed3e9c5a 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -435,7 +435,7 @@ void add_argv(struct argv_store *store, const char *what, int quoted) xtables_error(PARAMETER_PROBLEM, "Trying to store NULL argument\n"); - store->argv[store->argc] = strdup(what); + store->argv[store->argc] = xtables_strdup(what); store->argvattr[store->argc] = quoted; store->argv[++store->argc] = NULL; } diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 82815cae..77bc1493 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -369,6 +369,18 @@ void *xtables_realloc(void *ptr, size_t size) return p; } +char *xtables_strdup(const char *s) +{ + char *dup = strdup(s); + + if (!dup) { + perror("ip[6]tables: strdup failed"); + exit(1); + } + + return dup; +} + static char *get_modprobe(void) { int procfile; diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c index 0dcdf607..9d3ac5c8 100644 --- a/libxtables/xtoptions.c +++ b/libxtables/xtoptions.c @@ -604,9 +604,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb) unsigned int maxiter; int value; - wp_arg = lo_arg = strdup(cb->arg); - if (lo_arg == NULL) - xt_params->exit_err(RESOURCE_PROBLEM, "strdup"); + wp_arg = lo_arg = xtables_strdup(cb->arg); maxiter = entry->size / esize; if (maxiter == 0) @@ -747,9 +745,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb) xtopt_parse_host(cb); return; } - work = strdup(orig_arg); - if (work == NULL) - xt_params->exit_err(PARAMETER_PROBLEM, "strdup"); + work = xtables_strdup(orig_arg); p = strchr(work, '/'); /* by def this can't be NULL now */ *p++ = '\0'; /* @@ -1139,11 +1135,7 @@ struct xtables_lmap *xtables_lmap_init(const char *file) goto out; } lmap_this->id = id; - lmap_this->name = strdup(cur); - if (lmap_this->name == NULL) { - free(lmap_this); - goto out; - } + lmap_this->name = xtables_strdup(cur); lmap_this->next = NULL; if (lmap_prev != NULL) -- cgit v1.2.3 From 68ed965b35cdc7b55d4ebc0ba37c1ac078ccbafb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 15:15:37 +0200 Subject: extensions: libxt_string: Avoid buffer size warning for strncpy() If the target buffer does not need to be null-terminated, one may simply use memcpy() and thereby avoid any compiler warnings. Signed-off-by: Phil Sutter --- extensions/libxt_string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c index 7c6366cb..739a8e7f 100644 --- a/extensions/libxt_string.c +++ b/extensions/libxt_string.c @@ -81,7 +81,7 @@ parse_string(const char *s, struct xt_string_info *info) { /* xt_string does not need \0 at the end of the pattern */ if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) { - strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE); + memcpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE); info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE); return; } -- cgit v1.2.3 From ba863c4b07df03356e52748032984e5c67fd2675 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 3 Jun 2021 00:06:15 +0200 Subject: libxtables: extend xlate infrastructure This infrastructure extends the existing xlate infrastructure: - Extensions can define set dependencies through .xlate. The resulting set definition can be obtained through xt_xlate_set_get(). - Add xl_xlate_set_family() and xl_xlate_get_family() to store/fetch the family. The first client of this new xlate API is the connlimit extension, which is added in a follow up patch. Signed-off-by: Pablo Neira Ayuso --- configure.ac | 4 +-- include/xtables.h | 6 ++++ iptables/xtables-translate.c | 29 +++++++++++----- libxtables/xtables.c | 82 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 93 insertions(+), 28 deletions(-) diff --git a/configure.ac b/configure.ac index 6864378a..00ae60c5 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ AC_INIT([iptables], [1.8.7]) # See libtool.info "Libtool's versioning system" -libxtables_vcurrent=16 -libxtables_vage=4 +libxtables_vcurrent=17 +libxtables_vage=5 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) diff --git a/include/xtables.h b/include/xtables.h index 5b13f348..e51f4bfd 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -633,9 +633,15 @@ extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); struct xt_xlate *xt_xlate_alloc(int size); void xt_xlate_free(struct xt_xlate *xl); void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); +#define xt_xlate_rule_add xt_xlate_add +void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment); const char *xt_xlate_get_comment(struct xt_xlate *xl); +void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family); +uint8_t xt_xlate_get_family(struct xt_xlate *xl); const char *xt_xlate_get(struct xt_xlate *xl); +#define xt_xlate_rule_get xt_xlate_get +const char *xt_xlate_set_get(struct xt_xlate *xl); #ifdef XTABLES_INTERNAL diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 575fb320..33ba68ec 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -155,20 +155,33 @@ static int nft_rule_xlate_add(struct nft_handle *h, bool append) { struct xt_xlate *xl = xt_xlate_alloc(10240); + const char *set; int ret; + xl_xlate_set_family(xl, h->family); + ret = h->ops->xlate(cs, xl); + if (!ret) + goto err_out; + + set = xt_xlate_set_get(xl); + if (set[0]) { + printf("add set %s %s %s\n", family2str[h->family], p->table, + xt_xlate_set_get(xl)); + + if (!cs->restore && p->command != CMD_NONE) + printf("nft "); + } + if (append) { - xt_xlate_add(xl, "add rule %s %s %s ", - family2str[h->family], p->table, p->chain); + printf("add rule %s %s %s ", + family2str[h->family], p->table, p->chain); } else { - xt_xlate_add(xl, "insert rule %s %s %s ", - family2str[h->family], p->table, p->chain); + printf("insert rule %s %s %s ", + family2str[h->family], p->table, p->chain); } + printf("%s\n", xt_xlate_rule_get(xl)); - ret = h->ops->xlate(cs, xl); - if (ret) - printf("%s\n", xt_xlate_get(xl)); - +err_out: xt_xlate_free(xl); return ret; } diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 77bc1493..9fff1e0d 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -2330,32 +2330,42 @@ void get_kernel_version(void) #include +enum xt_xlate_type { + XT_XLATE_RULE = 0, + XT_XLATE_SET, + __XT_XLATE_MAX +}; + struct xt_xlate { - struct { + struct xt_xlate_buf { char *data; int size; int rem; int off; - } buf; + } buf[__XT_XLATE_MAX]; char comment[NFT_USERDATA_MAXLEN]; + int family; }; struct xt_xlate *xt_xlate_alloc(int size) { struct xt_xlate *xl; + int i; xl = malloc(sizeof(struct xt_xlate)); if (xl == NULL) xtables_error(RESOURCE_PROBLEM, "OOM"); - xl->buf.data = malloc(size); - if (xl->buf.data == NULL) - xtables_error(RESOURCE_PROBLEM, "OOM"); + for (i = 0; i < __XT_XLATE_MAX; i++) { + xl->buf[i].data = malloc(size); + if (xl->buf[i].data == NULL) + xtables_error(RESOURCE_PROBLEM, "OOM"); - xl->buf.data[0] = '\0'; - xl->buf.size = size; - xl->buf.rem = size; - xl->buf.off = 0; + xl->buf[i].data[0] = '\0'; + xl->buf[i].size = size; + xl->buf[i].rem = size; + xl->buf[i].off = 0; + } xl->comment[0] = '\0'; return xl; @@ -2363,23 +2373,44 @@ struct xt_xlate *xt_xlate_alloc(int size) void xt_xlate_free(struct xt_xlate *xl) { - free(xl->buf.data); + int i; + + for (i = 0; i < __XT_XLATE_MAX; i++) + free(xl->buf[i].data); + free(xl); } -void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) +static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type, + const char *fmt, va_list ap) { - va_list ap; + struct xt_xlate_buf *buf = &xl->buf[type]; int len; - va_start(ap, fmt); - len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap); - if (len < 0 || len >= xl->buf.rem) + len = vsnprintf(buf->data + buf->off, buf->rem, fmt, ap); + if (len < 0 || len >= buf->rem) xtables_error(RESOURCE_PROBLEM, "OOM"); + buf->rem -= len; + buf->off += len; +} + +void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + __xt_xlate_add(xl, XT_XLATE_RULE, fmt, ap); + va_end(ap); +} + +void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + __xt_xlate_add(xl, XT_XLATE_SET, fmt, ap); va_end(ap); - xl->buf.rem -= len; - xl->buf.off += len; } void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment) @@ -2393,7 +2424,22 @@ const char *xt_xlate_get_comment(struct xt_xlate *xl) return xl->comment[0] ? xl->comment : NULL; } +void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family) +{ + xl->family = family; +} + +uint8_t xt_xlate_get_family(struct xt_xlate *xl) +{ + return xl->family; +} + const char *xt_xlate_get(struct xt_xlate *xl) { - return xl->buf.data; + return xl->buf[XT_XLATE_RULE].data; +} + +const char *xt_xlate_set_get(struct xt_xlate *xl) +{ + return xl->buf[XT_XLATE_SET].data; } -- cgit v1.2.3 From 62828a6aff231e9f7f40c0321f7740f53070c2fb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 4 Jun 2021 00:19:40 +0200 Subject: tests: xlate-test: support multiline expectation Extend translation test to deal with multiline translation, e.g. iptables-translate -A INPUT -m connlimit --connlimit-above 2 nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter Signed-off-by: Pablo Neira Ayuso --- xlate-test.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 4c014f9b..cba98b6e 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -39,14 +39,21 @@ def run_test(name, payload): tests = passed = failed = errors = 0 result = [] - for line in payload: + line = payload.readline() + while line: if line.startswith(keywords): tests += 1 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") - expected = next(payload).rstrip(" \n") + expected = payload.readline().rstrip(" \n") + next_expected = payload.readline().rstrip(" \n") + if next_expected.startswith("nft"): + expected += "\n" + next_expected + line = payload.readline() + else: + line = next_expected if translation != expected: test_passed = False failed += 1 @@ -62,6 +69,9 @@ def run_test(name, payload): errors += 1 result.append(name + ": " + red("Error: ") + "iptables-translate failure") result.append(error.decode("utf-8")) + line = payload.readline() + else: + line = payload.readline() if (passed == tests) and not args.test: print(name + ": " + green("OK")) if not test_passed: -- cgit v1.2.3 From bb01e33d3828d08cd77cc3c9664b2a995ee150cc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 2 Jun 2021 19:57:37 +0200 Subject: extensions: libxt_connlimit: add translation This patch adds a translation for connlimit matches which requires the definition of a set and the family context (either IPv4 or IPv6) which is required to display the netmask accordingly. Signed-off-by: Pablo Neira Ayuso --- extensions/libxt_connlimit.c | 49 +++++++++++++++++++++++++++++++++++++++ extensions/libxt_connlimit.txlate | 15 ++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 extensions/libxt_connlimit.txlate diff --git a/extensions/libxt_connlimit.c b/extensions/libxt_connlimit.c index a569f86a..118faea5 100644 --- a/extensions/libxt_connlimit.c +++ b/extensions/libxt_connlimit.c @@ -2,6 +2,8 @@ #include #include #include +#include + #include enum { @@ -183,6 +185,51 @@ static void connlimit_save6(const void *ip, const struct xt_entry_match *match) } } +static int connlimit_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_connlimit_info *info = (const void *)params->match->data; + static uint32_t connlimit_id; + char netmask[128] = {}; + char addr[64] = {}; + uint32_t mask; + + switch (xt_xlate_get_family(xl)) { + case AF_INET: + mask = count_bits4(info->v4_mask); + if (mask != 32) { + struct in_addr *in = (struct in_addr *)&info->v4_mask; + + inet_ntop(AF_INET, in, addr, sizeof(addr)); + snprintf(netmask, sizeof(netmask), "and %s ", addr); + } + break; + case AF_INET6: + mask = count_bits6(info->v6_mask); + if (mask != 128) { + struct in6_addr *in6 = (struct in6_addr *)&info->v6_mask; + + inet_ntop(AF_INET6, in6, addr, sizeof(addr)); + snprintf(netmask, sizeof(netmask), "and %s ", addr); + } + break; + default: + return 0; + } + + xt_xlate_set_add(xl, "connlimit%u { type ipv4_addr; flags dynamic; }", + connlimit_id); + xt_xlate_rule_add(xl, "add @connlimit%u { %s %s %sct count %s%u }", + connlimit_id++, + xt_xlate_get_family(xl) == AF_INET ? "ip" : "ip6", + info->flags & XT_CONNLIMIT_DADDR ? "daddr" : "saddr", + netmask, + info->flags & XT_CONNLIMIT_INVERT ? "" : "over ", + info->limit); + + return 1; +} + static struct xtables_match connlimit_mt_reg[] = { { .name = "connlimit", @@ -228,6 +275,7 @@ static struct xtables_match connlimit_mt_reg[] = { .print = connlimit_print4, .save = connlimit_save4, .x6_options = connlimit_opts, + .xlate = connlimit_xlate, }, { .name = "connlimit", @@ -243,6 +291,7 @@ static struct xtables_match connlimit_mt_reg[] = { .print = connlimit_print6, .save = connlimit_save6, .x6_options = connlimit_opts, + .xlate = connlimit_xlate, }, }; diff --git a/extensions/libxt_connlimit.txlate b/extensions/libxt_connlimit.txlate new file mode 100644 index 00000000..758868c4 --- /dev/null +++ b/extensions/libxt_connlimit.txlate @@ -0,0 +1,15 @@ +iptables-translate -A INPUT -m connlimit --connlimit-above 2 +nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } +nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter + +iptables-translate -A INPUT -m connlimit --connlimit-upto 2 +nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } +nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter + +iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-mask 24 +nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } +nft add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter + +iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-daddr +nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } +nft add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter -- cgit v1.2.3 From 1c934617f661dc0bc471c0f0b4ace254c55182df Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 3 Jun 2021 01:46:06 +0200 Subject: extensions: libxt_tcp: rework translation to use flags match representation Use the new flags match representation available since nftables 0.9.9 to simplify the translation. Signed-off-by: Pablo Neira Ayuso --- extensions/libxt_TCPMSS.txlate | 4 ++-- extensions/libxt_tcp.c | 10 +++++----- extensions/libxt_tcp.txlate | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extensions/libxt_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate index 6a64d2ce..3dbbad66 100644 --- a/extensions/libxt_TCPMSS.txlate +++ b/extensions/libxt_TCPMSS.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set rt mtu +nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90 -nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set 90 +nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90 diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 383e4db5..0b115cdd 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -381,7 +381,7 @@ static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags) for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++); if (have_flag) - xt_xlate_add(xl, "|"); + xt_xlate_add(xl, ","); xt_xlate_add(xl, "%s", tcp_flag_names_xlate[i].name); have_flag = 1; @@ -435,11 +435,11 @@ static int tcp_xlate(struct xt_xlate *xl, return 0; if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { - xt_xlate_add(xl, "%stcp flags & (", space); - print_tcp_xlate(xl, tcpinfo->flg_mask); - xt_xlate_add(xl, ") %s ", - tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!=": "=="); + xt_xlate_add(xl, "%stcp flags %s", space, + tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": ""); print_tcp_xlate(xl, tcpinfo->flg_cmp); + xt_xlate_add(xl, " / "); + print_tcp_xlate(xl, tcpinfo->flg_mask); } return 1; diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate index bba63324..921d4af0 100644 --- a/extensions/libxt_tcp.txlate +++ b/extensions/libxt_tcp.txlate @@ -11,13 +11,13 @@ iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP -nft add rule ip filter INPUT tcp flags & fin|ack == fin counter drop +nft add rule ip filter INPUT tcp flags fin / fin,ack counter drop iptables-translate -A INPUT -p tcp --syn -j ACCEPT -nft add rule ip filter INPUT tcp flags & (fin|syn|rst|ack) == syn counter accept +nft add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 tcp flags & (fin|syn|rst|ack) == syn counter accept +nft add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept iptables-translate -A INPUT -f -p tcp nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter -- cgit v1.2.3 From c8145139cb230ff22837795c97f2e264c574c64c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 3 Jun 2021 01:58:43 +0200 Subject: extensions: libxt_conntrack: simplify translation using negation Available since nftables 0.9.9. For example: # iptables-translate -I INPUT -m state ! --state NEW,INVALID nft insert rule ip filter INPUT ct state ! invalid,new counter Signed-off-by: Pablo Neira Ayuso --- extensions/libxt_conntrack.c | 46 +++++++++++---------------------------- extensions/libxt_conntrack.txlate | 8 +++---- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 7f7b45ee..64018ce1 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1151,40 +1151,30 @@ static void state_save(const void *ip, const struct xt_entry_match *match) static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask, int inverted) { const char *sep = ""; - int one_flag_set; - one_flag_set = !(statemask & (statemask - 1)); - - if (inverted && !one_flag_set) - xt_xlate_add(xl, "& ("); - else if (inverted) - xt_xlate_add(xl, "& "); + if (inverted) + xt_xlate_add(xl, "! "); if (statemask & XT_CONNTRACK_STATE_INVALID) { xt_xlate_add(xl, "%s%s", sep, "invalid"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { xt_xlate_add(xl, "%s%s", sep, "new"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { xt_xlate_add(xl, "%s%s", sep, "related"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { xt_xlate_add(xl, "%s%s", sep, "established"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { xt_xlate_add(xl, "%s%s", sep, "untracked"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } - - if (inverted && !one_flag_set) - xt_xlate_add(xl, ") == 0"); - else if (inverted) - xt_xlate_add(xl, " == 0"); } static int state_xlate(struct xt_xlate *xl, @@ -1203,36 +1193,26 @@ static int state_xlate(struct xt_xlate *xl, static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask, int inverted) { const char *sep = ""; - int one_flag_set; - one_flag_set = !(statusmask & (statusmask - 1)); - - if (inverted && !one_flag_set) - xt_xlate_add(xl, "& ("); - else if (inverted) - xt_xlate_add(xl, "& "); + if (inverted) + xt_xlate_add(xl, "! "); if (statusmask & IPS_EXPECTED) { xt_xlate_add(xl, "%s%s", sep, "expected"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statusmask & IPS_SEEN_REPLY) { xt_xlate_add(xl, "%s%s", sep, "seen-reply"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statusmask & IPS_ASSURED) { xt_xlate_add(xl, "%s%s", sep, "assured"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } if (statusmask & IPS_CONFIRMED) { xt_xlate_add(xl, "%s%s", sep, "confirmed"); - sep = inverted && !one_flag_set ? "|" : ","; + sep = ","; } - - if (inverted && !one_flag_set) - xt_xlate_add(xl, ") == 0"); - else if (inverted) - xt_xlate_add(xl, " == 0"); } static void addr_xlate_print(struct xt_xlate *xl, diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index 8cc7c504..45fba984 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -2,10 +2,10 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCE nft add rule ip filter INPUT ct state new,related counter accept ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT -nft add rule ip6 filter INPUT ct state & (new|related) == 0 counter accept +nft add rule ip6 filter INPUT ct state ! new,related counter accept ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT -nft add rule ip6 filter INPUT ct state & new == 0 counter accept +nft add rule ip6 filter INPUT ct state ! new counter accept iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT nft add rule ip filter INPUT ct original protocol 17 counter accept @@ -35,10 +35,10 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT nft add rule ip filter INPUT ct status expected counter accept iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT -nft add rule ip filter INPUT ct status & confirmed == 0 counter accept +nft add rule ip filter INPUT ct status ! confirmed counter accept iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT -nft add rule ip filter INPUT ct status & (assured|confirmed) == 0 counter accept +nft add rule ip filter INPUT ct status ! assured,confirmed counter accept iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT nft add rule ip filter INPUT ct status assured,confirmed counter accept -- cgit v1.2.3 From 9e1fffdfeb29a0638e10fda3c0e984d3592e3124 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 25 Jun 2021 23:05:12 +0200 Subject: extensions: libxt_multiport: add translation for -m multiport --ports Add a translation for -m multiport --ports. Extend the existing testcase. Signed-off-by: Pablo Neira Ayuso --- extensions/libxt_multiport.c | 38 ++++++++++++++++++++++++++++++-------- extensions/libxt_multiport.txlate | 3 +++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c index 4a42fa38..6b0c8190 100644 --- a/extensions/libxt_multiport.c +++ b/extensions/libxt_multiport.c @@ -465,7 +465,8 @@ static void multiport_save6_v1(const void *ip_void, } static int __multiport_xlate(struct xt_xlate *xl, - const struct xt_xlate_mt_params *params) + const struct xt_xlate_mt_params *params, + uint8_t proto) { const struct xt_multiport *multiinfo = (const struct xt_multiport *)params->match->data; @@ -479,7 +480,17 @@ static int __multiport_xlate(struct xt_xlate *xl, xt_xlate_add(xl, " dport "); break; case XT_MULTIPORT_EITHER: - return 0; + xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto)); + for (i = 0; i < multiinfo->count; i++) { + if (i != 0) + xt_xlate_add(xl, ", "); + + xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535", + multiinfo->ports[i], multiinfo->ports[i]); + } + xt_xlate_add(xl, " }"); + + return 1; } if (multiinfo->count > 1) @@ -500,7 +511,7 @@ static int multiport_xlate(struct xt_xlate *xl, uint8_t proto = ((const struct ipt_ip *)params->ip)->proto; xt_xlate_add(xl, "%s", proto_to_name(proto)); - return __multiport_xlate(xl, params); + return __multiport_xlate(xl, params, proto); } static int multiport_xlate6(struct xt_xlate *xl, @@ -509,11 +520,12 @@ static int multiport_xlate6(struct xt_xlate *xl, uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto; xt_xlate_add(xl, "%s", proto_to_name(proto)); - return __multiport_xlate(xl, params); + return __multiport_xlate(xl, params, proto); } static int __multiport_xlate_v1(struct xt_xlate *xl, - const struct xt_xlate_mt_params *params) + const struct xt_xlate_mt_params *params, + uint8_t proto) { const struct xt_multiport_v1 *multiinfo = (const struct xt_multiport_v1 *)params->match->data; @@ -527,7 +539,17 @@ static int __multiport_xlate_v1(struct xt_xlate *xl, xt_xlate_add(xl, " dport "); break; case XT_MULTIPORT_EITHER: - return 0; + xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto)); + for (i = 0; i < multiinfo->count; i++) { + if (i != 0) + xt_xlate_add(xl, ", "); + + xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535", + multiinfo->ports[i], multiinfo->ports[i]); + } + xt_xlate_add(xl, " }"); + + return 1; } if (multiinfo->invert) @@ -556,7 +578,7 @@ static int multiport_xlate_v1(struct xt_xlate *xl, uint8_t proto = ((const struct ipt_ip *)params->ip)->proto; xt_xlate_add(xl, "%s", proto_to_name(proto)); - return __multiport_xlate_v1(xl, params); + return __multiport_xlate_v1(xl, params, proto); } static int multiport_xlate6_v1(struct xt_xlate *xl, @@ -565,7 +587,7 @@ static int multiport_xlate6_v1(struct xt_xlate *xl, uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto; xt_xlate_add(xl, "%s", proto_to_name(proto)); - return __multiport_xlate_v1(xl, params); + return __multiport_xlate_v1(xl, params, proto); } static struct xtables_match multiport_mt_reg[] = { diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate index 752e7148..bced1b84 100644 --- a/extensions/libxt_multiport.txlate +++ b/extensions/libxt_multiport.txlate @@ -9,3 +9,6 @@ nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept + +iptables-translate -t filter -I INPUT -p tcp -m multiport --ports 10 +nft insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter -- cgit v1.2.3 From e727ccad036e2cdba3339536c65c7ceef43c0740 Mon Sep 17 00:00:00 2001 From: Erik Wilson Date: Tue, 13 Jul 2021 16:48:23 -0700 Subject: xtables: Call init_extensions6() for static builds Initialize extensions from libext6 for cases where xtables is built statically. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1550 Signed-off-by: Erik Wilson Signed-off-by: Florian Westphal --- iptables/xtables-monitor.c | 1 + iptables/xtables-restore.c | 1 + iptables/xtables-save.c | 1 + iptables/xtables-standalone.c | 1 + iptables/xtables-translate.c | 1 + 5 files changed, 5 insertions(+) diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 4b980980..21d4bec0 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -628,6 +628,7 @@ int xtables_monitor_main(int argc, char *argv[]) #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); + init_extensions6(); #endif if (nft_init(&h, AF_INET, xtables_ipv4)) { diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index d2739497..72832103 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -364,6 +364,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); + init_extensions6(); #endif break; case NFPROTO_ARP: diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index cfce0472..98cd0ed3 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -203,6 +203,7 @@ xtables_save_main(int family, int argc, char *argv[], #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); + init_extensions6(); #endif tables = xtables_ipv4; d.commit = true; diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 7b71db62..1a6b7cf7 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -57,6 +57,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); + init_extensions6(); #endif if (nft_init(&h, family, xtables_ipv4) < 0) { diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 33ba68ec..49f44b6f 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -482,6 +482,7 @@ static int xtables_xlate_main_common(struct nft_handle *h, #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); + init_extensions6(); #endif tables = xtables_ipv4; break; -- cgit v1.2.3 From 765bf04ecc228783cb88c810c85bc0c769579c39 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 28 Jul 2021 17:53:53 +0200 Subject: doc: ebtables-nft.8: Adjust for missing atomic-options Drop any reference to them (and the environment variable) but list them in BUGS section hinting at ebtables-save and -restore tools. Fixes: 1939cbc25e6f5 ("doc: Adjust ebtables man page") Signed-off-by: Phil Sutter Acked-by: Pablo Neira Ayuso --- iptables/ebtables-nft.8 | 64 +++++++------------------------------------------ 1 file changed, 8 insertions(+), 56 deletions(-) diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index 1fa5ad93..08e9766f 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -44,12 +44,6 @@ ebtables \- Ethernet bridge frame table administration (nft-based) .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 @@ -149,11 +143,9 @@ 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 +are combined or the commands .BR -N " and " -P -are combined, or when -.B --atomic-file -is used. +are combined. .TP .B "-A, --append" Append a rule to the end of the selected chain. @@ -313,39 +305,6 @@ 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" @@ -371,16 +330,6 @@ 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 @@ -1100,8 +1049,6 @@ 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 @@ -1109,7 +1056,12 @@ The version of ebtables this man page ships with does not support the .B broute table. Also there is no support for .B string -match. And finally, this list is probably not complete. +match. Further, support for atomic-options +.RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit ) +has not been implemented, although +.BR ebtables-save " and " ebtables-restore +might replace them entirely given the inherent atomicity of nftables. +Finally, this list is probably not complete. .SH SEE ALSO .BR xtables-nft "(8), " iptables "(8), " ip (8) .PP -- cgit v1.2.3 From 263186372dc4ae6a54a29bea644bcf1fc8dc3fc0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 30 Jul 2021 12:25:10 +0200 Subject: ebtables: Dump atomic waste With ebtables-nft.8 now educating people about the missing functionality, get rid of atomic remains in source code. This eliminates mostly comments except for --atomic-commit which was treated as alias of --init-table. People not using the latter are probably trying to atomic-commit from an atomic-file which in turn is not supported, so no point keeping it. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 53 --------------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 6c58adaa..6e35f58e 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -211,10 +211,6 @@ struct option ebt_original_options[] = { "new-chain" , required_argument, 0, 'N' }, { "rename-chain" , required_argument, 0, 'E' }, { "delete-chain" , optional_argument, 0, 'X' }, - { "atomic-init" , no_argument , 0, 7 }, - { "atomic-commit" , no_argument , 0, 8 }, - { "atomic-file" , required_argument, 0, 9 }, - { "atomic-save" , no_argument , 0, 10 }, { "init-table" , no_argument , 0, 11 }, { "concurrent" , no_argument , 0, 13 }, { 0 } @@ -320,10 +316,6 @@ static void print_help(const struct xtables_target *t, "--new-chain -N chain : create a user defined chain\n" "--rename-chain -E old new : rename a chain\n" "--delete-chain -X [chain] : delete a user defined chain\n" -"--atomic-commit : update the kernel w/t table contained in \n" -"--atomic-init : put the initial kernel table into \n" -"--atomic-save : put the current kernel table into \n" -"--atomic-file file : set to file\n\n" "Options:\n" "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n" "--src -s [!] address[/mask]: source mac address\n" @@ -1087,54 +1079,9 @@ print_zero: "Use --Lmac2 with -L"); flags |= LIST_MAC2; break; - case 8 : /* atomic-commit */ -/* - replace->command = c; - if (OPT_COMMANDS) - ebt_print_error2("Multiple commands are not allowed"); - replace->flags |= OPT_COMMAND; - if (!replace->filename) - ebt_print_error2("No atomic file specified");*/ - /* Get the information from the file */ - /*ebt_get_table(replace, 0);*/ - /* We don't want the kernel giving us its counters, - * they would overwrite the counters extracted from - * the file */ - /*replace->num_counters = 0;*/ - /* Make sure the table will be written to the kernel */ - /*free(replace->filename); - replace->filename = NULL; - break;*/ - /*case 7 :*/ /* atomic-init */ - /*case 10:*/ /* atomic-save */ case 11: /* init-table */ nft_cmd_table_flush(h, *table, false); return 1; - /* - replace->command = c; - if (OPT_COMMANDS) - ebt_print_error2("Multiple commands are not allowed"); - if (c != 11 && !replace->filename) - ebt_print_error2("No atomic file specified"); - replace->flags |= OPT_COMMAND; - { - char *tmp = replace->filename;*/ - - /* Get the kernel table */ - /*replace->filename = NULL; - ebt_get_kernel_table(replace, c == 10 ? 0 : 1); - replace->filename = tmp; - } - break; - case 9 :*/ /* atomic */ - /* - if (OPT_COMMANDS) - ebt_print_error2("--atomic has to come before the command");*/ - /* A possible memory leak here, but this is not - * executed in daemon mode */ - /*replace->filename = (char *)malloc(strlen(optarg) + 1); - strcpy(replace->filename, optarg); - break; */ case 13 : break; case 1 : -- cgit v1.2.3 From 57d1422dbbc41c36ed2e9f6c67aa040c65a429a0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 3 Aug 2021 10:55:20 +0200 Subject: nft: Fix for non-verbose check command Check command was unconditionally verbose since v1.8.5. Make it respect --verbose option again. Fixes: a7f1e208cdf9c ("nft: split parsing from netlink commands") Signed-off-by: Phil Sutter --- iptables/nft.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft.c b/iptables/nft.c index f1deb82f..795dff86 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3126,7 +3126,7 @@ static int nft_prepare(struct nft_handle *h) case NFT_COMPAT_RULE_CHECK: assert_chain_exists(h, cmd->table, cmd->jumpto); ret = nft_rule_check(h, cmd->chain, cmd->table, - cmd->obj.rule, cmd->rulenum); + cmd->obj.rule, cmd->verbose); break; case NFT_COMPAT_RULE_ZERO: ret = nft_rule_zero_counters(h, cmd->chain, cmd->table, -- cgit v1.2.3 From 8629c53f933a16f1d68d19fb163c879453a3dcf2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 3 Aug 2021 11:32:34 +0200 Subject: tests/shell: Assert non-verbose mode is silent Unexpected output from iptables commands might mess up error-checking in scripts for instance, so do a quick test of the most common commands. Note: Test adds two rules to make sure flush command operates on a non-empty chain. Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/iptables/0002-verbose-output_0 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index b1ef91f6..5d2af4c8 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -54,3 +54,14 @@ diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar) diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar) diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar) + +# make sure non-verbose mode is silent +diff -u <(echo -n "") <( + $XT_MULTI iptables -N foobar + $XT_MULTI iptables -A foobar $RULE1 + $XT_MULTI iptables -A foobar $RULE2 + $XT_MULTI iptables -C foobar $RULE1 + $XT_MULTI iptables -D foobar $RULE2 + $XT_MULTI iptables -F foobar + $XT_MULTI iptables -X foobar +) -- cgit v1.2.3 From ef7781eb1437a2d6fd37eb3567c599e3ea682b96 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 19 Jul 2021 16:35:09 +0200 Subject: libxtables: exit if called by setuid executeable iptables (legacy or nft, doesn't matter) cannot be safely used with setuid binaries. Add a safety check for this. Signed-off-by: Florian Westphal --- libxtables/xtables.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 9fff1e0d..b261e97b 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -245,6 +245,10 @@ static void dlreg_free(void) void xtables_init(void) { + /* xtables cannot be used with setuid in a safe way. */ + if (getuid() != geteuid()) + _exit(111); + xtables_libdir = getenv("XTABLES_LIBDIR"); if (xtables_libdir != NULL) return; -- cgit v1.2.3 From 943fbf3e1850ae1f52f29c2f4f2aca399779b368 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Wed, 4 Aug 2021 18:50:57 +0300 Subject: ip6tables: masquerade: use fully-random so that nft can understand the rule Here is the problem: []# nft -v nftables v0.9.8 (E.D.S.) []# iptables-nft -v iptables v1.8.7 (nf_tables): no command specified Try `iptables -h' or 'iptables --help' for more information. []# nft flush ruleset []# ip6tables-nft -t nat -A POSTROUTING -j MASQUERADE --random-full []# nft list ruleset table ip6 nat { chain POSTROUTING { type nat hook postrouting priority srcnat; policy accept; counter packets 0 bytes 0 masquerade random-fully } } []# nft list ruleset > /tmp/ruleset []# nft flush ruleset []# nft -f /tmp/ruleset /tmp/ruleset:4:54-54: Error: syntax error, unexpected newline counter packets 0 bytes 0 masquerade random-fully That's because nft list ruleset saves "random-fully" which is wrong format for nft -f, right should be "fully-random". We face this problem because we run k8s in Virtuozzo container, and k8s creates those "random-fully" rules by iptables(nft) and then CRIU can't restore those rules using nft. Signed-off-by: Pavel Tikhomirov Signed-off-by: Florian Westphal --- extensions/libip6t_MASQUERADE.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c index f92760fa..f28f071b 100644 --- a/extensions/libip6t_MASQUERADE.c +++ b/extensions/libip6t_MASQUERADE.c @@ -163,7 +163,7 @@ static int MASQUERADE_xlate(struct xt_xlate *xl, xt_xlate_add(xl, " "); if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - xt_xlate_add(xl, "random-fully "); + xt_xlate_add(xl, "fully-random "); return 1; } -- cgit v1.2.3 From bef9dc575625a98a5e6ed8ca37e49031cdba5937 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 9 Aug 2021 18:48:58 +0200 Subject: extensions: hashlimit: Fix tests with HZ=100 With the kernel ticking at 100Hz, a limit of 1/day with burst 5 does not overflow in kernel, making the test unstable depending on kernel config. Change it to not overflow with 1000Hz either by increasing the burst value by a factor of 100. Fixes: fcf9f6f25db11 ("extensions: libxt_hashlimit: add unit test") Signed-off-by: Phil Sutter --- extensions/libxt_hashlimit.t | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t index ccd0d1e6..83699337 100644 --- a/extensions/libxt_hashlimit.t +++ b/extensions/libxt_hashlimit.t @@ -3,14 +3,12 @@ -m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK -# kernel says "xt_hashlimit: overflow, try lower: 864000000/5" --m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL +-m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK -# kernel says "xt_hashlimit: overflow, try lower: 864000000/5" --m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL +-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -- cgit v1.2.3 From 7ae14dc1a938fc158aaa1761b4fba57c5f1ab7a0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 11 Aug 2021 14:46:22 +0200 Subject: iptables-test: Make netns spawning more robust On systems without unshare Python module, try to call unshare binary with oneself as parameters. Signed-off-by: Phil Sutter --- iptables-test.py | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index ca5efb1b..90e07fee 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -304,6 +304,31 @@ def show_missing(): print('\n'.join(missing)) +def spawn_netns(): + # prefer unshare module + try: + import unshare + unshare.unshare(unshare.CLONE_NEWNET) + return True + except: + pass + + # sledgehammer style: + # - call ourselves prefixed by 'unshare -n' if found + # - pass extra --no-netns parameter to avoid another recursion + try: + import shutil + + unshare = shutil.which("unshare") + if unshare is None: + return False + + sys.argv.append("--no-netns") + os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv) + except: + pass + + return False # # main @@ -323,6 +348,8 @@ def main(): help='Test iptables-over-nftables') parser.add_argument('-N', '--netns', action='store_true', help='Test netnamespace path') + parser.add_argument('--no-netns', action='store_true', + help='Do not run testsuite in own network namespace') args = parser.parse_args() # @@ -341,6 +368,9 @@ def main(): print("You need to be root to run this, sorry") return + if not args.netns and not args.no_netns and not spawn_netns(): + print("Cannot run in own namespace, connectivity might break") + if not args.host: os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH)) os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), @@ -366,13 +396,6 @@ def main(): if i.endswith('.t')] file_list.sort() - if not args.netns: - try: - import unshare - unshare.unshare(unshare.CLONE_NEWNET) - except: - print("Cannot run in own namespace, connectivity might break") - for filename in file_list: file_tests, file_passed = run_test_file(filename, args.netns) if file_tests: -- cgit v1.2.3 From cf410aa6604d92faf2a2a5051ec18b7d9482e752 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 30 Aug 2021 23:48:54 +0200 Subject: extensions: libxt_mac: Fix for missing space in listing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Listing the extension using 'iptables -L', there was no space between 'MAC' and the following Address. Reported-by: Adam Wójcik Fixes: 1bdb5535f561a ("libxtables: Extend MAC address printing/parsing support") Signed-off-by: Phil Sutter --- extensions/libxt_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c index b90eef20..55891b2b 100644 --- a/extensions/libxt_mac.c +++ b/extensions/libxt_mac.c @@ -42,10 +42,10 @@ mac_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_mac_info *info = (void *)match->data; - printf(" MAC"); + printf(" MAC "); if (info->invert) - printf(" !"); + printf("! "); xtables_print_mac(info->srcaddr); } -- cgit v1.2.3 From ca11c7b7036b5821c17b8d08dc2a29f55b461a93 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 31 Aug 2021 12:26:20 +0200 Subject: nft: Use xtables_malloc() in mnl_err_list_node_add() The function called malloc() without checking for memory allocation failure. Simply replace the call by xtables_malloc() to fix that. Fixes: 4e2020952d6f9 ("xtables: use libnftnl batch API") Signed-off-by: Phil Sutter --- iptables/nft.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft.c b/iptables/nft.c index 795dff86..a470939d 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -143,7 +143,7 @@ struct mnl_err { static void mnl_err_list_node_add(struct list_head *err_list, int error, int seqnum) { - struct mnl_err *err = malloc(sizeof(struct mnl_err)); + struct mnl_err *err = xtables_malloc(sizeof(struct mnl_err)); err->seqnum = seqnum; err->err = error; -- cgit v1.2.3 From e438b9766fcc86d9847312ff05f1d1dac61acf1f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 31 Aug 2021 12:29:43 +0200 Subject: nft: Use xtables_{m,c}alloc() everywhere Make use of libxtables allocators where sensible to have implicit error checking. Leave library-internal calls in place to not create unexpected program exit points for users, apart from xt_xlate_alloc() as that function called xtables_error() in error case which exits by itself already. Signed-off-by: Phil Sutter --- iptables/nft-bridge.c | 6 +----- iptables/nft-cmd.c | 5 +---- iptables/nft.c | 15 +++------------ iptables/xshared.c | 8 ++------ iptables/xtables-eb.c | 14 +++----------- libxtables/xtables.c | 11 ++--------- 6 files changed, 12 insertions(+), 47 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index d98fd527..11f3df35 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -477,11 +477,7 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, static void parse_watcher(void *object, struct ebt_match **match_list, bool ismatch) { - struct ebt_match *m; - - m = calloc(1, sizeof(struct ebt_match)); - if (m == NULL) - xtables_error(OTHER_PROBLEM, "Can't allocate memory"); + struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match)); if (ismatch) m->u.match = object; diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index a0c76a79..87e66905 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -23,10 +23,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, struct nftnl_rule *rule; struct nft_cmd *cmd; - cmd = calloc(1, sizeof(struct nft_cmd)); - if (!cmd) - return NULL; - + cmd = xtables_calloc(1, sizeof(struct nft_cmd)); cmd->command = command; cmd->table = xtables_strdup(table); if (chain) diff --git a/iptables/nft.c b/iptables/nft.c index a470939d..c9ed38bd 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -362,10 +362,7 @@ static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type t { struct obj_update *obj; - obj = calloc(1, sizeof(struct obj_update)); - if (obj == NULL) - return NULL; - + obj = xtables_calloc(1, sizeof(struct obj_update)); obj->ptr = ptr; obj->error.lineno = h->error.lineno; obj->type = type; @@ -997,10 +994,7 @@ static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m) nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name)); nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision); - info = calloc(1, m->u.match_size); - if (info == NULL) - return -ENOMEM; - + info = xtables_calloc(1, m->u.match_size); memcpy(info, m->data, m->u.match_size - sizeof(*m)); nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m)); @@ -1245,10 +1239,7 @@ static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t) strlen(t->u.user.name)); nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision); - info = calloc(1, t->u.target_size); - if (info == NULL) - return -ENOMEM; - + info = xtables_calloc(1, t->u.target_size); memcpy(info, t->data, t->u.target_size - sizeof(*t)); nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t)); diff --git a/iptables/xshared.c b/iptables/xshared.c index ed3e9c5a..2d3ef679 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -220,9 +220,7 @@ void xs_init_target(struct xtables_target *target) { if (target->udata_size != 0) { free(target->udata); - target->udata = calloc(1, target->udata_size); - if (target->udata == NULL) - xtables_error(RESOURCE_PROBLEM, "malloc"); + target->udata = xtables_calloc(1, target->udata_size); } if (target->init != NULL) target->init(target->t); @@ -238,9 +236,7 @@ void xs_init_match(struct xtables_match *match) * Same goes for target. */ free(match->udata); - match->udata = calloc(1, match->udata_size); - if (match->udata == NULL) - xtables_error(RESOURCE_PROBLEM, "malloc"); + match->udata = xtables_calloc(1, match->udata_size); } if (match->init != NULL) match->init(match->m); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 6e35f58e..6e5ecd48 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -274,9 +274,7 @@ static struct option *merge_options(struct option *oldopts, ebtables_globals.option_offset += OPTION_OFFSET; *options_offset = ebtables_globals.option_offset; - merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); - if (!merge) - return NULL; + merge = xtables_malloc(sizeof(struct option) * (num_new + num_old + 1)); memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; @@ -571,10 +569,7 @@ void ebt_add_match(struct xtables_match *m, m->mflags = 0; /* glue code for watchers */ - newnode = calloc(1, sizeof(struct ebt_match)); - if (newnode == NULL) - xtables_error(OTHER_PROBLEM, "Unable to alloc memory"); - + newnode = xtables_calloc(1, sizeof(struct ebt_match)); newnode->ismatch = true; newnode->u.match = newm; @@ -603,10 +598,7 @@ void ebt_add_watcher(struct xtables_target *watcher, watcher->tflags = 0; - newnode = calloc(1, sizeof(struct ebt_match)); - if (newnode == NULL) - xtables_error(OTHER_PROBLEM, "Unable to alloc memory"); - + newnode = xtables_calloc(1, sizeof(struct ebt_match)); newnode->u.watcher = clone; for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index b261e97b..d670175d 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -2353,18 +2353,11 @@ struct xt_xlate { struct xt_xlate *xt_xlate_alloc(int size) { - struct xt_xlate *xl; + struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate)); int i; - xl = malloc(sizeof(struct xt_xlate)); - if (xl == NULL) - xtables_error(RESOURCE_PROBLEM, "OOM"); - for (i = 0; i < __XT_XLATE_MAX; i++) { - xl->buf[i].data = malloc(size); - if (xl->buf[i].data == NULL) - xtables_error(RESOURCE_PROBLEM, "OOM"); - + xl->buf[i].data = xtables_malloc(size); xl->buf[i].data[0] = '\0'; xl->buf[i].size = size; xl->buf[i].rem = size; -- cgit v1.2.3 From 544e7dc1541e4db3abc9896ff757e7642c97738e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Thu, 2 Sep 2021 13:33:59 +0200 Subject: Fix a few doc typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just a few minor language fixes. Signed-off-by: Štěpán Němec Signed-off-by: Phil Sutter --- extensions/libxt_devgroup.man | 2 +- iptables/xtables-monitor.8.in | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_devgroup.man b/extensions/libxt_devgroup.man index 4a66c9fe..480ee351 100644 --- a/extensions/libxt_devgroup.man +++ b/extensions/libxt_devgroup.man @@ -1,4 +1,4 @@ -Match device group of a packets incoming/outgoing interface. +Match device group of a packet's incoming/outgoing interface. .TP [\fB!\fP] \fB\-\-src\-group\fP \fIname\fP Match device group of incoming device diff --git a/iptables/xtables-monitor.8.in b/iptables/xtables-monitor.8.in index b647a79e..a7f22c0d 100644 --- a/iptables/xtables-monitor.8.in +++ b/iptables/xtables-monitor.8.in @@ -51,9 +51,9 @@ The second line dumps information about the packet. Incoming interface and packet headers such as source and destination addresses are shown. The third line shows that the packet completed traversal of the raw table -PREROUTING chain, and is returning, followed by use the chain policy to make accept/drop +PREROUTING chain, and is returning, followed by use of the chain policy to make accept/drop decision (the example shows accept being applied). -The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter tables +The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter table's INPUT chain matched the packet. It then got DROPPED by the policy of the INPUT table, as shown by line six. The last line shows another packet arriving \-\- the packet id is different. @@ -81,7 +81,7 @@ by three base hooks INPUT, FORWARD and OUTPUT. The iptables-nftables tools all chains automatically when needed, so this is expected when a table was not yet initialized or when it is re-created from scratch by iptables-nftables-restore. Line five shows a new user-defined chain (TCP) being added, followed by addition a few rules. the last line shows that a new ruleset generation has -become active, i.e., the rule set changes are now active. This also lists the process id and the programs name. +become active, i.e., the rule set changes are now active. This also lists the process id and the program name. .SH LIMITATIONS .B xtables-monitor only works with rules added using iptables-nftables, rules added using -- cgit v1.2.3 From 61e85e3192deaff3b9dd1eb9270863acc7a26311 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 14 Aug 2021 19:46:43 +0200 Subject: iptables-nft: allow removal of empty builtin chains The only reason why this is prohibited is that you cannot do it in iptables-legacy. This removes the artifical limitation. "iptables-nft -X" will leave the builtin chains alone; Also, deletion is only permitted if the chain is empty. Signed-off-by: Florian Westphal --- iptables/iptables.8.in | 13 +++++---- iptables/nft-cmd.c | 8 +++--- iptables/nft-cmd.h | 4 +-- iptables/nft.c | 78 +++++++++++++++++++++++++++++++++----------------- iptables/nft.h | 4 +-- iptables/xtables-arp.c | 4 +-- iptables/xtables-eb.c | 2 +- iptables/xtables.c | 4 +-- 8 files changed, 72 insertions(+), 45 deletions(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 999cf339..759ec54f 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -25,10 +25,10 @@ .SH NAME iptables/ip6tables \(em administration tool for IPv4/IPv6 packet filtering and NAT .SH SYNOPSIS -\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP} +\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP} \fIchain\fP \fIrule-specification\fP .P -\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP} +\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP} \fIchain rule-specification\fP .PP \fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-I\fP \fIchain\fP [\fIrulenum\fP] \fIrule-specification\fP @@ -220,11 +220,11 @@ Create a new user-defined chain by the given name. There must be no target of that name already. .TP \fB\-X\fP, \fB\-\-delete\-chain\fP [\fIchain\fP] -Delete the optional user-defined chain specified. There must be no references +Delete the chain specified. There must be no references to the chain. If there are, you must delete or replace the referring rules before the chain can be deleted. The chain must be empty, i.e. not contain -any rules. If no argument is given, it will attempt to delete every -non-builtin chain in the table. +any rules. If no argument is given, it will delete all empty chains in the +table. Empty builtin chains can only be deleted with \fBiptables-nft\fP. .TP \fB\-P\fP, \fB\-\-policy\fP \fIchain target\fP Set the policy for the built-in (non-user-defined) chain to the given target. @@ -362,6 +362,9 @@ For appending, insertion, deletion and replacement, this causes detailed information on the rule or rules to be printed. \fB\-v\fP may be specified multiple times to possibly emit more detailed debug statements. .TP +\fB\-V\fP, \fB\-\-version\fP +Show program version and the kernel API used. +.TP \fB\-w\fP, \fB\-\-wait\fP [\fIseconds\fP] Wait for the xtables lock. To prevent multiple instances of the program from running concurrently, diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 87e66905..35b39268 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -205,12 +205,12 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain, return 1; } -int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain, - const char *table, bool verbose) +int nft_cmd_chain_del(struct nft_handle *h, const char *chain, + const char *table, bool verbose) { struct nft_cmd *cmd; - cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1, + cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_DEL, table, chain, NULL, -1, verbose); if (!cmd) return 0; @@ -317,7 +317,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose) if (verbose) { return nft_cmd_rule_flush(h, NULL, table, verbose) && - nft_cmd_chain_user_del(h, NULL, table, verbose); + nft_cmd_chain_del(h, NULL, table, verbose); } cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1, diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h index ecf7655a..b5a99ef7 100644 --- a/iptables/nft-cmd.h +++ b/iptables/nft-cmd.h @@ -49,8 +49,8 @@ int nft_cmd_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain, const char *table); -int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain, - const char *table, bool verbose); +int nft_cmd_chain_del(struct nft_handle *h, const char *chain, + const char *table, bool verbose); int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_cmd_rule_list(struct nft_handle *h, const char *chain, diff --git a/iptables/nft.c b/iptables/nft.c index c9ed38bd..89dde9ec 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -290,7 +290,7 @@ static int mnl_append_error(const struct nft_handle *h, [NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH", [NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD", [NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD", - [NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL", + [NFT_COMPAT_CHAIN_DEL] = "CHAIN_DEL", [NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH", [NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE", [NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME", @@ -321,7 +321,7 @@ static int mnl_append_error(const struct nft_handle *h, case NFT_COMPAT_CHAIN_ADD: case NFT_COMPAT_CHAIN_ZERO: case NFT_COMPAT_CHAIN_USER_ADD: - case NFT_COMPAT_CHAIN_USER_DEL: + case NFT_COMPAT_CHAIN_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: case NFT_COMPAT_CHAIN_RENAME: @@ -1836,22 +1836,19 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table #define NLM_F_NONREC 0x100 /* Do not delete recursively */ #endif -struct chain_user_del_data { +struct chain_del_data { struct nft_handle *handle; + struct nft_cache *cache; + enum nft_table_type type; bool verbose; - int builtin_err; }; -static int __nft_chain_user_del(struct nft_chain *nc, void *data) +static int __nft_chain_del(struct nft_chain *nc, void *data) { - struct chain_user_del_data *d = data; + struct chain_del_data *d = data; struct nftnl_chain *c = nc->nftnl; struct nft_handle *h = d->handle; - /* don't delete built-in chain */ - if (nft_chain_builtin(c)) - return d->builtin_err; - if (d->verbose) fprintf(stdout, "Deleting chain `%s'\n", nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); @@ -1859,9 +1856,16 @@ static int __nft_chain_user_del(struct nft_chain *nc, void *data) /* XXX This triggers a fast lookup from the kernel. */ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); - if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c)) + if (!batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c)) return -1; + if (nft_chain_builtin(c)) { + uint32_t num = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); + + if (nc == d->cache->table[d->type].base_chains[num]) + d->cache->table[d->type].base_chains[num] = NULL; + } + /* nftnl_chain is freed when deleting the batch object */ nc->nftnl = NULL; @@ -1870,17 +1874,18 @@ static int __nft_chain_user_del(struct nft_chain *nc, void *data) return 0; } -int nft_chain_user_del(struct nft_handle *h, const char *chain, +int nft_chain_del(struct nft_handle *h, const char *chain, const char *table, bool verbose) { - struct chain_user_del_data d = { + const struct builtin_table *t; + struct chain_del_data d = { .handle = h, .verbose = verbose, }; struct nft_chain *c; int ret = 0; - nft_fn = nft_chain_user_del; + nft_fn = nft_chain_del; if (chain) { c = nft_chain_find(h, table, chain); @@ -1888,17 +1893,37 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, errno = ENOENT; return 0; } - d.builtin_err = -2; - ret = __nft_chain_user_del(c, &d); + + if (nft_chain_builtin(c->nftnl)) { + t = nft_table_builtin_find(h, table); + if (!t) { + errno = EINVAL; + return 0; + } + + d.type = t->type; + d.cache = h->cache; + } + + ret = __nft_chain_del(c, &d); if (ret == -2) errno = EINVAL; goto out; } + t = nft_table_builtin_find(h, table); + if (!t) { + errno = EINVAL; + return 0; + } + + d.type = t->type; + d.cache = h->cache; + if (verbose) nft_cache_sort_chains(h, table); - ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d); + ret = nft_chain_foreach(h, table, __nft_chain_del, &d); out: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -2663,7 +2688,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) case NFT_COMPAT_CHAIN_USER_ADD: case NFT_COMPAT_CHAIN_ADD: break; - case NFT_COMPAT_CHAIN_USER_DEL: + case NFT_COMPAT_CHAIN_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: case NFT_COMPAT_CHAIN_RENAME: @@ -2748,7 +2773,7 @@ static void nft_refresh_transaction(struct nft_handle *h) 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_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: case NFT_COMPAT_CHAIN_RENAME: @@ -2814,7 +2839,7 @@ retry: NLM_F_EXCL, n->seq, n->chain); break; - case NFT_COMPAT_CHAIN_USER_DEL: + case NFT_COMPAT_CHAIN_DEL: nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN, NLM_F_NONREC, n->seq, n->chain); @@ -3059,9 +3084,9 @@ static int nft_prepare(struct nft_handle *h) case NFT_COMPAT_CHAIN_USER_ADD: ret = nft_chain_user_add(h, cmd->chain, cmd->table); break; - case NFT_COMPAT_CHAIN_USER_DEL: - ret = nft_chain_user_del(h, cmd->chain, cmd->table, - cmd->verbose); + case NFT_COMPAT_CHAIN_DEL: + ret = nft_chain_del(h, cmd->chain, cmd->table, + cmd->verbose); break; case NFT_COMPAT_CHAIN_RESTORE: ret = nft_chain_restore(h, cmd->chain, cmd->table); @@ -3260,10 +3285,9 @@ const char *nft_strerror(int err) const char *message; } table[] = { - { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" }, - { nft_chain_user_del, EINVAL, "Can't delete built-in chain" }, - { nft_chain_user_del, EBUSY, "Directory not empty" }, - { nft_chain_user_del, EMLINK, + { nft_chain_del, ENOTEMPTY, "Chain is not empty" }, + { nft_chain_del, EBUSY, "Directory not empty" }, + { nft_chain_del, EMLINK, "Can't delete chain with references left" }, { nft_chain_user_add, EEXIST, "Chain already exists" }, { nft_chain_user_rename, EEXIST, "File exists" }, diff --git a/iptables/nft.h b/iptables/nft.h index 4ac7e009..a7b652ff 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -53,7 +53,7 @@ enum obj_update_type { NFT_COMPAT_TABLE_FLUSH, NFT_COMPAT_CHAIN_ADD, NFT_COMPAT_CHAIN_USER_ADD, - NFT_COMPAT_CHAIN_USER_DEL, + NFT_COMPAT_CHAIN_DEL, NFT_COMPAT_CHAIN_USER_FLUSH, NFT_COMPAT_CHAIN_UPDATE, NFT_COMPAT_CHAIN_RENAME, @@ -147,7 +147,7 @@ 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); int nft_chain_save(struct nft_chain *c, void *data); 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_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); 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); diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 4a351f0c..9a079f06 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -893,8 +893,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, ret = nft_cmd_chain_user_add(h, chain, *table); break; case CMD_DELETE_CHAIN: - ret = nft_cmd_chain_user_del(h, chain, *table, - options & OPT_VERBOSE); + ret = nft_cmd_chain_del(h, chain, *table, + options & OPT_VERBOSE); break; case CMD_RENAME_CHAIN: ret = nft_cmd_chain_user_rename(h, chain, *table, newname); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 6e5ecd48..23023ce1 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -771,7 +771,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, chain = argv[optind]; optind++; } - ret = nft_cmd_chain_user_del(h, chain, *table, 0); + ret = nft_cmd_chain_del(h, chain, *table, 0); break; } diff --git a/iptables/xtables.c b/iptables/xtables.c index daa9b137..0a700e08 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -998,8 +998,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, ret = nft_cmd_chain_user_add(h, p.chain, p.table); break; case CMD_DELETE_CHAIN: - ret = nft_cmd_chain_user_del(h, p.chain, p.table, - cs.options & OPT_VERBOSE); + ret = nft_cmd_chain_del(h, p.chain, p.table, + cs.options & OPT_VERBOSE); break; case CMD_RENAME_CHAIN: ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname); -- cgit v1.2.3 From fcbe454bf0d05612a8484723fd3e9299d4ee836f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Aug 2021 19:11:59 +0200 Subject: tests: iptables-test: Fix missing chain case If a chain line was really missing, Python complained about reference before assignment of 'chain_array' variable. While being at it, reuse print_error() function for reporting and allow to continue with the next input file instead of exiting. Signed-off-by: Phil Sutter --- iptables-test.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 90e07fee..01966f91 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -215,6 +215,7 @@ def run_test_file(filename, netns): tests = 0 passed = 0 table = "" + chain_array = [] total_test_passed = True if netns: @@ -249,8 +250,10 @@ def run_test_file(filename, netns): continue if len(chain_array) == 0: - print("broken test, missing chain, leaving") - sys.exit() + print_error("broken test, missing chain", + filename = filename, lineno = lineno) + total_test_passed = False + break test_passed = True tests += 1 -- cgit v1.2.3 From fa78ff15602598a5a0f229055455e67757539372 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 6 Sep 2021 12:52:22 +0200 Subject: tests: xlate-test: Don't skip any input after the first empty line In conditionals, testing the empty string evaluates to false. This is dumb but seems intentional, as readline() method returns an empty string at EOF. This is distinct from reading an empty line as the latter contains the newline character - unless it is stripped in between readline() and conditional. The fixed commit introduced just that by accident, effectively reducing any test file to the first contained test: | $ ./xlate-test.py | [...] | 81 test files, 84 tests, 84 tests passed, 0 tests failed, 0 errors With this change in place, the summary looks much better: | 81 test files, 368 tests, 368 tests passed, 0 tests failed, 0 errors Fixes: 62828a6aff231 ("tests: xlate-test: support multiline expectation") Signed-off-by: Phil Sutter --- xlate-test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index cba98b6e..1fa5eca3 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -48,9 +48,9 @@ def run_test(name, payload): if process.returncode == 0: translation = output.decode("utf-8").rstrip(" \n") expected = payload.readline().rstrip(" \n") - next_expected = payload.readline().rstrip(" \n") + next_expected = payload.readline() if next_expected.startswith("nft"): - expected += "\n" + next_expected + expected += "\n" + next_expected.rstrip(" \n") line = payload.readline() else: line = next_expected -- cgit v1.2.3 From 5166c4451fb837e7d5dbb54a7d7cbf2f0c2469cc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Aug 2021 15:12:30 +0200 Subject: tests: xlate-test: Print errors to stderr Return code is always zero, so grepping for output on stderr is a simple way to detect testsuite failures. Signed-off-by: Phil Sutter --- xlate-test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 1fa5eca3..bb7a447d 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -75,7 +75,7 @@ def run_test(name, payload): if (passed == tests) and not args.test: print(name + ": " + green("OK")) if not test_passed: - print("\n".join(result)) + print("\n".join(result), file=sys.stderr) if args.test: print("1 test file, %d tests, %d tests passed, %d tests failed, %d errors" % (tests, passed, failed, errors)) else: @@ -111,7 +111,7 @@ def main(): with open(args.test, "r") as payload: run_test(args.test, payload) except IOError: - print(red("Error: ") + "test file does not exist") + print(red("Error: ") + "test file does not exist", file=sys.stderr) else: load_test_files() -- cgit v1.2.3 From a8da71864d467c4371dc24cd763fa2c1dfb6cfbb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Aug 2021 19:14:13 +0200 Subject: tests: iptables-test: Print errors to stderr No big deal, just pass the extra parameter to the four error print calls. Signed-off-by: Phil Sutter --- iptables-test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 01966f91..1790da3d 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -47,7 +47,7 @@ def print_error(reason, filename=None, lineno=None): Prints an error with nice colors, indicating file and line number. ''' print(filename + ": " + Colors.RED + "ERROR" + - Colors.ENDC + ": line %d (%s)" % (lineno, reason)) + Colors.ENDC + ": line %d (%s)" % (lineno, reason), file=sys.stderr) def delete_rule(iptables, rule, filename, lineno): @@ -368,11 +368,12 @@ def main(): EXECUTEABLE = "xtables-nft-multi" if os.getuid() != 0: - print("You need to be root to run this, sorry") + print("You need to be root to run this, sorry", file=sys.stderr) return if not args.netns and not args.no_netns and not spawn_netns(): - print("Cannot run in own namespace, connectivity might break") + print("Cannot run in own namespace, connectivity might break", + file=sys.stderr) if not args.host: os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH)) @@ -388,7 +389,7 @@ def main(): try: log_file = open(LOGFILE, 'w') except IOError: - print("Couldn't open log file %s" % LOGFILE) + print("Couldn't open log file %s" % LOGFILE, file=sys.stderr) return if args.filename: -- cgit v1.2.3 From c057939d80cc6219a137784c195e14ee1bc62a58 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 6 Sep 2021 13:07:43 +0200 Subject: tests: xlate-test: Exit non-zero on error If a test fails, return a non-zero exit code. To do so, propagate the pass/fail statistics up to main() for evaluation. While being at it, move the statistics printing into there as well and get rid of that redundant assignment to 'test_passed'. Signed-off-by: Phil Sutter --- xlate-test.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index bb7a447d..4a56e798 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -61,7 +61,6 @@ def run_test(name, payload): result.append(magenta("src: ") + line.rstrip(" \n")) result.append(magenta("exp: ") + expected) result.append(magenta("res: ") + translation + "\n") - test_passed = False else: passed += 1 else: @@ -76,10 +75,7 @@ def run_test(name, payload): print(name + ": " + green("OK")) if not test_passed: print("\n".join(result), file=sys.stderr) - if args.test: - print("1 test file, %d tests, %d tests passed, %d tests failed, %d errors" % (tests, passed, failed, errors)) - else: - return tests, passed, failed, errors + return tests, passed, failed, errors def load_test_files(): @@ -93,10 +89,9 @@ def load_test_files(): total_passed += passed total_failed += failed total_error += errors + return (test_files, total_tests, total_passed, total_failed, total_error) - 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(): global xtables_nft_multi if not args.host: @@ -104,16 +99,27 @@ def main(): xtables_nft_multi = os.path.abspath(os.path.curdir) \ + '/iptables/' + xtables_nft_multi + files = tests = passed = failed = errors = 0 if args.test: if not args.test.endswith(".txlate"): args.test += ".txlate" try: with open(args.test, "r") as payload: - run_test(args.test, payload) + files = 1 + tests, passed, failed, errors = run_test(args.test, payload) except IOError: print(red("Error: ") + "test file does not exist", file=sys.stderr) + return -1 + else: + files, tests, passed, failed, errors = load_test_files() + + if files > 1: + file_word = "files" else: - load_test_files() + file_word = "file" + print("%d test %s, %d tests, %d tests passed, %d tests failed, %d errors" + % (files, file_word, tests, passed, failed, errors)) + return passed - tests parser = argparse.ArgumentParser() @@ -121,4 +127,4 @@ 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() +sys.exit(main()) -- cgit v1.2.3 From 7559af835d8f58375f797f895e1a5410027127d9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 6 Sep 2021 13:49:34 +0200 Subject: tests: iptables-test: Exit non-zero on error If any test fails, return a non-zero exit code. Signed-off-by: Phil Sutter --- iptables-test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables-test.py b/iptables-test.py index 1790da3d..5eafe589 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -408,7 +408,8 @@ def main(): test_files += 1 print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed)) + return passed - tests if __name__ == '__main__': - main() + sys.exit(main()) -- cgit v1.2.3 From 481626bb4e9c51477ec99dde0727e3af69d2380f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 6 Sep 2021 17:28:30 +0200 Subject: tests: shell: Return non-zero on error If any test fails, return a non-zero exit code. Signed-off-by: Phil Sutter --- iptables/tests/shell/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index 65c37adb..7878760f 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -195,4 +195,4 @@ failed=$((legacy_fail+failed)) msg_info "combined results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))" -exit 0 +exit -$failed -- cgit v1.2.3 From b714d45dc4c2423d4df4cbf7ccf238ec441675ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Thu, 2 Sep 2021 13:33:07 +0200 Subject: iptables-test.py: print with color escapes only when stdout isatty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the output doesn't go to a terminal (typical case: log files), the escape sequences are just noise. Signed-off-by: Štěpán Němec Signed-off-by: Phil Sutter --- iptables-test.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 5eafe589..a876f616 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -32,22 +32,25 @@ EXTENSIONS_PATH = "extensions" LOGFILE="/tmp/iptables-test.log" log_file = None +STDOUT_IS_TTY = sys.stdout.isatty() -class Colors: - HEADER = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' +def maybe_colored(color, text): + terminal_sequences = { + 'green': '\033[92m', + 'red': '\033[91m', + } + + return ( + terminal_sequences[color] + text + '\033[0m' if STDOUT_IS_TTY else text + ) def print_error(reason, filename=None, lineno=None): ''' Prints an error with nice colors, indicating file and line number. ''' - print(filename + ": " + Colors.RED + "ERROR" + - Colors.ENDC + ": line %d (%s)" % (lineno, reason), file=sys.stderr) + print(filename + ": " + maybe_colored('red', "ERROR") + + ": line %d (%s)" % (lineno, reason), file=sys.stderr) def delete_rule(iptables, rule, filename, lineno): @@ -285,7 +288,7 @@ def run_test_file(filename, netns): if netns: execute_cmd("ip netns del ____iptables-container-test", filename, 0) if total_test_passed: - print(filename + ": " + Colors.GREEN + "OK" + Colors.ENDC) + print(filename + ": " + maybe_colored('green', "OK")) f.close() return tests, passed -- cgit v1.2.3 From 63ab4fe3a1919b668953542841f4397544c4bb15 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 15 Sep 2021 17:37:51 +0200 Subject: ebtables: Avoid dropping policy when flushing Unlike nftables, ebtables' user-defined chains have policies - ebtables-nft implements those internally as invisible last rule. In order to recreate them after a flush command, a rule cache is needed. https://bugzilla.netfilter.org/show_bug.cgi?id=1558 --- iptables/nft-cmd.c | 4 ++- .../shell/testcases/ebtables/0007-chain-policies_0 | 41 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 35b39268..2d874bd4 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -167,7 +167,9 @@ int nft_cmd_rule_flush(struct nft_handle *h, const char *chain, if (!cmd) return 0; - if (chain || verbose) + if (h->family == NFPROTO_BRIDGE) + nft_cache_level_set(h, NFT_CL_RULES, cmd); + else if (chain || verbose) nft_cache_level_set(h, NFT_CL_CHAINS, cmd); else nft_cache_level_set(h, NFT_CL_TABLES, cmd); diff --git a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 new file mode 100755 index 00000000..faf37d02 --- /dev/null +++ b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 @@ -0,0 +1,41 @@ +#!/bin/sh + +case "$XT_MULTI" in +*xtables-nft-multi) + ;; +*) + echo "skip $XT_MULTI" + exit 0 + ;; +esac + +set -e + +# ebtables supports policies in user-defined chains %) +# and the default policy is ACCEPT ... +$XT_MULTI ebtables -N FOO -P DROP +$XT_MULTI ebtables -N BAR +$XT_MULTI ebtables -P BAR RETURN +$XT_MULTI ebtables -N BAZ + +EXPECT_BASE="*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT" + +EXPECT="$EXPECT_BASE +:BAR RETURN +:BAZ ACCEPT +:FOO DROP" + +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#') + +# rule commands must not break the policies +$XT_MULTI ebtables -A FOO -j ACCEPT +$XT_MULTI ebtables -D FOO -j ACCEPT +$XT_MULTI ebtables -F +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#') + +# dropping the chains must implicitly remove the policy rule as well +$XT_MULTI ebtables -X +diff -u -Z <(echo -e "$EXPECT_BASE") <($XT_MULTI ebtables-save | grep -v '^#') -- cgit v1.2.3 From 2ed6dc7557b8c4a70bfd81684a72737312d7bd4b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 15 Sep 2021 17:47:15 +0200 Subject: tests: iptables-test: Fix conditional colors on stderr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Štěpán's patch to make colored output depend on whether output is a TTY clashed with my change to print errors to stderr instead of stdout. Fix this by telling maybe_colored() if it should print colors or not as only caller knows where output is sent to. Signed-off-by: Phil Sutter --- iptables-test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index a876f616..0ba3d368 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -33,15 +33,16 @@ LOGFILE="/tmp/iptables-test.log" log_file = None STDOUT_IS_TTY = sys.stdout.isatty() +STDERR_IS_TTY = sys.stderr.isatty() -def maybe_colored(color, text): +def maybe_colored(color, text, isatty): terminal_sequences = { 'green': '\033[92m', 'red': '\033[91m', } return ( - terminal_sequences[color] + text + '\033[0m' if STDOUT_IS_TTY else text + terminal_sequences[color] + text + '\033[0m' if isatty else text ) @@ -49,7 +50,7 @@ def print_error(reason, filename=None, lineno=None): ''' Prints an error with nice colors, indicating file and line number. ''' - print(filename + ": " + maybe_colored('red', "ERROR") + + print(filename + ": " + maybe_colored('red', "ERROR", STDERR_IS_TTY) + ": line %d (%s)" % (lineno, reason), file=sys.stderr) @@ -288,7 +289,7 @@ def run_test_file(filename, netns): if netns: execute_cmd("ip netns del ____iptables-container-test", filename, 0) if total_test_passed: - print(filename + ": " + maybe_colored('green', "OK")) + print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) f.close() return tests, passed -- cgit v1.2.3 From 040a15f27075ccded8d819af6cf0484c532515ef Mon Sep 17 00:00:00 2001 From: "mizuta.takeshi@fujitsu.com" Date: Wed, 22 Sep 2021 14:26:00 +0000 Subject: xtables-translate: add missing argument and option to usage In xtables-restore-translate usage, the argument for the -f option and the -V|--version option are missing, so added them. Signed-off-by: MIZUTA Takeshi Signed-off-by: Florian Westphal --- iptables/xtables-translate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 49f44b6f..2a00a850 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -354,9 +354,10 @@ static void print_usage(const char *name, const char *version) { fprintf(stderr, "%s %s " "(c) 2014 by Pablo Neira Ayuso \n" - "Usage: %s [-h] [-f]\n" + "Usage: %s [-h] [-f ] [-V]\n" " [ --help ]\n" - " [ --file= ]\n", name, version, name); + " [ --file= ]\n" + " [ --version ]\n", name, version, name); exit(1); } -- cgit v1.2.3 From 4318961230bce82958df82b57f1796143bf2f421 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 21 Sep 2021 11:39:45 +0200 Subject: nft: cache: Avoid double free of unrecognized base-chains On error, nft_cache_add_chain() frees the allocated nft_chain object along with the nftnl_chain it points at. Fix nftnl_chain_list_cb() to not free the nftnl_chain again in that case. Fixes: 176c92c26bfc9 ("nft: Introduce a dedicated base chain array") Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 4 +--- .../tests/shell/testcases/chain/0004extra-base_0 | 27 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100755 iptables/tests/shell/testcases/chain/0004extra-base_0 diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 2c88301c..9a03bbfb 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -314,9 +314,7 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) goto out; } - if (nft_cache_add_chain(h, t, c)) - goto out; - + nft_cache_add_chain(h, t, c); return MNL_CB_OK; out: nftnl_chain_free(c); diff --git a/iptables/tests/shell/testcases/chain/0004extra-base_0 b/iptables/tests/shell/testcases/chain/0004extra-base_0 new file mode 100755 index 00000000..1b85b060 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0004extra-base_0 @@ -0,0 +1,27 @@ +#!/bin/bash + +case $XT_MULTI in +*xtables-nft-multi) + ;; +*) + echo skip $XT_MULTI + exit 0 + ;; +esac + +set -e + +nft -f - < Date: Tue, 21 Sep 2021 16:42:36 +0200 Subject: nft: Check base-chain compatibility when adding to cache With introduction of dedicated base-chain slots, a selection process was established as no longer all base-chains ended in the same chain list for later searching/checking but only the first one found for each hook matching criteria is kept and the rest discarded. A side-effect of the above is that table compatibility checking started to omit consecutive base-chains, making iptables-nft less restrictive as long as the expected base-chains were returned first from kernel when populating the cache. Make behaviour consistent and warn users about the possibly disturbing chains found by: * Run all base-chain checks from nft_is_chain_compatible() before allowing a base-chain to occupy its slot. * If an unfit base-chain was found (and discarded), flag the table's cache as tainted and warn about it if the remaining ruleset is otherwise compatible. Since base-chains that remain in cache would pass nft_is_chain_compatible() checking, remove that and reduce it to rule inspection. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 47 +++++++++++++++++----- iptables/nft.c | 45 ++++++--------------- iptables/nft.h | 2 + .../tests/shell/testcases/chain/0004extra-base_0 | 12 +++++- iptables/xtables-save.c | 3 ++ 5 files changed, 65 insertions(+), 44 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 9a03bbfb..b7f10ab9 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -202,26 +202,51 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) return NULL; } +static int +nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t, + struct nft_chain *nc) +{ + uint32_t hooknum = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_HOOKNUM); + const char *name = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_NAME); + const char *type = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_TYPE); + uint32_t prio = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_PRIO); + const struct builtin_chain *bc = NULL; + int i; + + for (i = 0; i < NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) { + if (hooknum == t->chains[i].hook) { + bc = &t->chains[i]; + break; + } + } + + if (!bc || + prio != bc->prio || + strcmp(name, bc->name) || + strcmp(type, bc->type)) + return -EINVAL; + + if (h->cache->table[t->type].base_chains[hooknum]) + return -EEXIST; + + h->cache->table[t->type].base_chains[hooknum] = nc; + return 0; +} + int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t, struct nftnl_chain *c) { const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); struct nft_chain *nc = nft_chain_alloc(c); + int ret; if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); - - if (hooknum >= NF_INET_NUMHOOKS) { + ret = nft_cache_add_base_chain(h, t, nc); + if (ret) { + h->cache->table[t->type].tainted = true; nft_chain_free(nc); - return -EINVAL; + return ret; } - - if (h->cache->table[t->type].base_chains[hooknum]) { - nft_chain_free(nc); - return -EEXIST; - } - - h->cache->table[t->type].base_chains[hooknum] = nc; } else { list_add_tail(&nc->head, &h->cache->table[t->type].chains->list); diff --git a/iptables/nft.c b/iptables/nft.c index 89dde9ec..17e735aa 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3513,38 +3513,8 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data) static int nft_is_chain_compatible(struct nft_chain *nc, void *data) { struct nftnl_chain *c = nc->nftnl; - 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; - - if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL)) - return -1; - - if (!nft_chain_builtin(c)) - return 0; - - tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - table = nft_table_builtin_find(h, tname); - if (!table) - return -1; - - cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - chain = nft_chain_builtin_find(table, cname); - if (!chain) - return -1; - 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 0; + return nftnl_rule_foreach(c, nft_is_rule_compatible, NULL); } bool nft_is_table_compatible(struct nft_handle *h, @@ -3559,13 +3529,24 @@ bool nft_is_table_compatible(struct nft_handle *h, return !nft_chain_foreach(h, table, nft_is_chain_compatible, h); } +bool nft_is_table_tainted(struct nft_handle *h, const char *table) +{ + const struct builtin_table *t = nft_table_builtin_find(h, table); + + return t ? h->cache->table[t->type].tainted : false; +} + void nft_assert_table_compatible(struct nft_handle *h, const char *table, const char *chain) { const char *pfx = "", *sfx = ""; - if (nft_is_table_compatible(h, table, chain)) + if (nft_is_table_compatible(h, table, chain)) { + if (nft_is_table_tainted(h, table)) + printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n", + table); return; + } if (chain) { pfx = "chain `"; diff --git a/iptables/nft.h b/iptables/nft.h index a7b652ff..ef79b018 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -45,6 +45,7 @@ struct nft_cache { struct nftnl_set_list *sets; bool exists; bool sorted; + bool tainted; } table[NFT_TABLE_MAX]; }; @@ -262,6 +263,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 *table, const char *chain); +bool nft_is_table_tainted(struct nft_handle *h, const char *table); void nft_assert_table_compatible(struct nft_handle *h, const char *table, const char *chain); diff --git a/iptables/tests/shell/testcases/chain/0004extra-base_0 b/iptables/tests/shell/testcases/chain/0004extra-base_0 index 1b85b060..cc07e4be 100755 --- a/iptables/tests/shell/testcases/chain/0004extra-base_0 +++ b/iptables/tests/shell/testcases/chain/0004extra-base_0 @@ -13,6 +13,10 @@ set -e nft -f - < Date: Fri, 17 Sep 2021 16:51:33 +0200 Subject: nft-chain: Introduce base_slot field For builtin chains, record the base_chains array slot they are assigned to. This simplifies removing that reference if they are being deleted later. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 5 +++-- iptables/nft-chain.h | 1 + iptables/nft.c | 28 +--------------------------- 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index b7f10ab9..43ac291e 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -226,10 +226,11 @@ nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t, strcmp(type, bc->type)) return -EINVAL; - if (h->cache->table[t->type].base_chains[hooknum]) + nc->base_slot = &h->cache->table[t->type].base_chains[hooknum]; + if (*nc->base_slot) return -EEXIST; - h->cache->table[t->type].base_chains[hooknum] = nc; + *nc->base_slot = nc; return 0; } diff --git a/iptables/nft-chain.h b/iptables/nft-chain.h index 137f4b7f..9adf1738 100644 --- a/iptables/nft-chain.h +++ b/iptables/nft-chain.h @@ -9,6 +9,7 @@ struct nft_handle; struct nft_chain { struct list_head head; struct hlist_node hnode; + struct nft_chain **base_slot; struct nftnl_chain *nftnl; }; diff --git a/iptables/nft.c b/iptables/nft.c index 17e735aa..38106147 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1838,8 +1838,6 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table struct chain_del_data { struct nft_handle *handle; - struct nft_cache *cache; - enum nft_table_type type; bool verbose; }; @@ -1860,10 +1858,7 @@ static int __nft_chain_del(struct nft_chain *nc, void *data) return -1; if (nft_chain_builtin(c)) { - uint32_t num = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); - - if (nc == d->cache->table[d->type].base_chains[num]) - d->cache->table[d->type].base_chains[num] = NULL; + *nc->base_slot = NULL; } /* nftnl_chain is freed when deleting the batch object */ @@ -1877,7 +1872,6 @@ static int __nft_chain_del(struct nft_chain *nc, void *data) int nft_chain_del(struct nft_handle *h, const char *chain, const char *table, bool verbose) { - const struct builtin_table *t; struct chain_del_data d = { .handle = h, .verbose = verbose, @@ -1894,32 +1888,12 @@ int nft_chain_del(struct nft_handle *h, const char *chain, return 0; } - if (nft_chain_builtin(c->nftnl)) { - t = nft_table_builtin_find(h, table); - if (!t) { - errno = EINVAL; - return 0; - } - - d.type = t->type; - d.cache = h->cache; - } - ret = __nft_chain_del(c, &d); if (ret == -2) errno = EINVAL; goto out; } - t = nft_table_builtin_find(h, table); - if (!t) { - errno = EINVAL; - return 0; - } - - d.type = t->type; - d.cache = h->cache; - if (verbose) nft_cache_sort_chains(h, table); -- cgit v1.2.3 From 45d8f7690eb449fb8cc8191025d93f73cfc7f498 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 14 Sep 2021 12:15:29 +0200 Subject: nft: Delete builtin chains compatibly Attempting to delete all chains if --delete-chain is called without argument has unwanted side-effects especially legacy iptables users are not aware of and won't expect: * Non-default policies are ignored, a previously dropping firewall may start accepting traffic. * The kernel refuses to remove non-empty chains, causing program abort even if no user-defined chain exists. Fix this by requiring a rule cache in that situation and make builtin chain deletion depend on its policy and number of rules. Since this may change concurrently, check again when having to refresh the transaction. Also, hide builtin chains from verbose output - their creation is implicit, so treat their removal as implicit, too. When deleting a specific chain, do not allow to skip the job though. Otherwise deleting a builtin chain which is still in use will succeed although not executed. Fixes: 61e85e3192dea ("iptables-nft: allow removal of empty builtin chains") Signed-off-by: Phil Sutter --- iptables/nft-cmd.c | 2 +- iptables/nft.c | 39 +++++++++++++++++----- .../tests/shell/testcases/chain/0005base-delete_0 | 34 +++++++++++++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100755 iptables/tests/shell/testcases/chain/0005base-delete_0 diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 2d874bd4..fcd01bd0 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -220,7 +220,7 @@ int nft_cmd_chain_del(struct nft_handle *h, const char *chain, /* This triggers nft_bridge_chain_postprocess() when fetching the * rule cache. */ - if (h->family == NFPROTO_BRIDGE) + if (h->family == NFPROTO_BRIDGE || !chain) nft_cache_level_set(h, NFT_CL_RULES, cmd); else nft_cache_level_set(h, NFT_CL_CHAINS, cmd); diff --git a/iptables/nft.c b/iptables/nft.c index 38106147..dc1f5160 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1838,26 +1838,46 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table struct chain_del_data { struct nft_handle *handle; + const char *chain; bool verbose; }; +static bool nft_may_delete_chain(struct nftnl_chain *c) +{ + if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY) && + nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY) != NF_ACCEPT) + return false; + + return nftnl_rule_lookup_byindex(c, 0) == NULL; +} + static int __nft_chain_del(struct nft_chain *nc, void *data) { struct chain_del_data *d = data; struct nftnl_chain *c = nc->nftnl; struct nft_handle *h = d->handle; + bool builtin = nft_chain_builtin(c); + struct obj_update *obj; + int ret = 0; - if (d->verbose) + if (d->verbose && !builtin) fprintf(stdout, "Deleting chain `%s'\n", nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); /* XXX This triggers a fast lookup from the kernel. */ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); - if (!batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c)) + obj = batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c); + if (!obj) return -1; - if (nft_chain_builtin(c)) { + if (builtin) { + obj->skip = !nft_may_delete_chain(c); + if (obj->skip && d->chain) { + /* complain if explicitly requested */ + errno = EBUSY; + ret = -1; + } *nc->base_slot = NULL; } @@ -1866,14 +1886,15 @@ static int __nft_chain_del(struct nft_chain *nc, void *data) nft_chain_list_del(nc); nft_chain_free(nc); - return 0; + return ret; } int nft_chain_del(struct nft_handle *h, const char *chain, - const char *table, bool verbose) + const char *table, bool verbose) { struct chain_del_data d = { .handle = h, + .chain = chain, .verbose = verbose, }; struct nft_chain *c; @@ -1889,8 +1910,6 @@ int nft_chain_del(struct nft_handle *h, const char *chain, } ret = __nft_chain_del(c, &d); - if (ret == -2) - errno = EINVAL; goto out; } @@ -2744,10 +2763,14 @@ static void nft_refresh_transaction(struct nft_handle *h) n->skip = !nft_chain_find(h, tablename, chainname); break; + case NFT_COMPAT_CHAIN_DEL: + if (!nftnl_chain_get(n->chain, NFTNL_CHAIN_HOOKNUM)) + break; + n->skip = !nft_may_delete_chain(n->chain); + break; case NFT_COMPAT_TABLE_ADD: case NFT_COMPAT_CHAIN_ADD: case NFT_COMPAT_CHAIN_ZERO: - case NFT_COMPAT_CHAIN_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: case NFT_COMPAT_CHAIN_RENAME: diff --git a/iptables/tests/shell/testcases/chain/0005base-delete_0 b/iptables/tests/shell/testcases/chain/0005base-delete_0 new file mode 100755 index 00000000..033a2819 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0005base-delete_0 @@ -0,0 +1,34 @@ +#!/bin/bash -x + +$XT_MULTI iptables -N foo || exit 1 +$XT_MULTI iptables -P FORWARD DROP || exit 1 +$XT_MULTI iptables -X || exit 1 +$XT_MULTI iptables -X foo && exit 1 + +# indefinite -X fails if a non-empty user-defined chain exists +$XT_MULTI iptables -N foo +$XT_MULTI iptables -N bar +$XT_MULTI iptables -A bar -j ACCEPT +$XT_MULTI iptables -X && exit 1 +$XT_MULTI iptables -D bar -j ACCEPT +$XT_MULTI iptables -X || exit 1 + +# make sure OUTPUT chain is created by iptables-nft +$XT_MULTI iptables -A OUTPUT -j ACCEPT || exit 1 +$XT_MULTI iptables -D OUTPUT -j ACCEPT || exit 1 + +case $XT_MULTI in +*xtables-nft-multi) + # must not delete chain FORWARD, its policy is not ACCEPT + $XT_MULTI iptables -X FORWARD && exit 1 + nft list chain ip filter FORWARD || exit 1 + # this should evict chain OUTPUT + $XT_MULTI iptables -X OUTPUT || exit 1 + nft list chain ip filter OUTPUT && exit 1 + ;; +*) + $XT_MULTI iptables -X FORWARD && exit 1 + $XT_MULTI iptables -X OUTPUT && exit 1 + ;; +esac +exit 0 -- cgit v1.2.3 From db90ff64fb89144d1e2ba18bc0569486cd5af9a3 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 20:12:28 +0100 Subject: tests: shell: fix bashism The `<(cmd)` redirection is specific to Bash. Update the shebang accordingly. Fixes: 63ab4fe3a191 ("ebtables: Avoid dropping policy when flushing") Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 index faf37d02..d79f91b1 100755 --- a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 +++ b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash case "$XT_MULTI" in *xtables-nft-multi) -- cgit v1.2.3 From 2e6014c739852daf8c0c42caeef01d3966622c4b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft: Introduce builtin_tables_lookup() The set of builtin tables to use is fully determined by the given family so just look it up instead of having callers pass it explicitly. Signed-off-by: Phil Sutter --- iptables/nft.c | 19 +++++++++++++++++-- iptables/nft.h | 2 +- iptables/xtables-arp.c | 2 +- iptables/xtables-eb.c | 2 +- iptables/xtables-monitor.c | 2 +- iptables/xtables-restore.c | 7 +------ iptables/xtables-save.c | 6 +----- iptables/xtables-standalone.c | 2 +- iptables/xtables-translate.c | 7 +------ 9 files changed, 25 insertions(+), 24 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index dc1f5160..1d3f3a3d 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -863,7 +863,22 @@ int nft_restart(struct nft_handle *h) return 0; } -int nft_init(struct nft_handle *h, int family, const struct builtin_table *t) +static const struct builtin_table *builtin_tables_lookup(int family) +{ + switch (family) { + case AF_INET: + case AF_INET6: + return xtables_ipv4; + case NFPROTO_ARP: + return xtables_arp; + case NFPROTO_BRIDGE: + return xtables_bridge; + default: + return NULL; + } +} + +int nft_init(struct nft_handle *h, int family) { memset(h, 0, sizeof(*h)); @@ -881,7 +896,7 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t) xtables_error(PARAMETER_PROBLEM, "Unknown family"); h->portid = mnl_socket_get_portid(h->nl); - h->tables = t; + h->tables = builtin_tables_lookup(family); h->cache = &h->__cache[0]; h->family = family; diff --git a/iptables/nft.h b/iptables/nft.h index ef79b018..f189b03f 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -123,7 +123,7 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX]; int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int (*cb)(const struct nlmsghdr *nlh, void *data), void *data); -int nft_init(struct nft_handle *h, int family, const struct builtin_table *t); +int nft_init(struct nft_handle *h, int family); void nft_fini(struct nft_handle *h); int nft_restart(struct nft_handle *h); diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 9a079f06..1d132bdf 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -397,7 +397,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname) init_extensionsa(); #endif - if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0) + if (nft_init(h, NFPROTO_ARP) < 0) xtables_error(OTHER_PROBLEM, "Could not initialize nftables layer."); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 23023ce1..1ed6bcd8 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -672,7 +672,7 @@ int nft_init_eb(struct nft_handle *h, const char *pname) init_extensionsb(); #endif - if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0) + if (nft_init(h, NFPROTO_BRIDGE) < 0) xtables_error(OTHER_PROBLEM, "Could not initialize nftables layer."); diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 21d4bec0..73dc80c2 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -631,7 +631,7 @@ int xtables_monitor_main(int argc, char *argv[]) init_extensions6(); #endif - if (nft_init(&h, AF_INET, xtables_ipv4)) { + if (nft_init(&h, AF_INET)) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 72832103..86dcede3 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -281,7 +281,6 @@ void xtables_restore_parse(struct nft_handle *h, static int xtables_restore_main(int family, const char *progname, int argc, char *argv[]) { - const struct builtin_table *tables; struct nft_xt_restore_parse p = { .commit = true, .cb = &restore_cb, @@ -360,7 +359,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthough, same table */ - tables = xtables_ipv4; #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); @@ -368,17 +366,14 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) #endif break; case NFPROTO_ARP: - tables = xtables_arp; - break; case NFPROTO_BRIDGE: - tables = xtables_bridge; break; default: fprintf(stderr, "Unknown family %d\n", family); return 1; } - if (nft_init(&h, family, tables) < 0) { + if (nft_init(&h, family) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index f794e3ff..c6ebb0ec 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -131,7 +131,6 @@ static int xtables_save_main(int family, int argc, char *argv[], const char *optstring, const struct option *longopts) { - const struct builtin_table *tables; const char *tablename = NULL; struct do_output_data d = { .format = FMT_NOCOUNTS, @@ -208,11 +207,9 @@ xtables_save_main(int family, int argc, char *argv[], init_extensions4(); init_extensions6(); #endif - tables = xtables_ipv4; d.commit = true; break; case NFPROTO_ARP: - tables = xtables_arp; break; case NFPROTO_BRIDGE: { const char *ctr = getenv("EBTABLES_SAVE_COUNTER"); @@ -223,7 +220,6 @@ xtables_save_main(int family, int argc, char *argv[], d.format &= ~FMT_NOCOUNTS; d.format |= FMT_C_COUNTS | FMT_EBT_SAVE; } - tables = xtables_bridge; break; } default: @@ -231,7 +227,7 @@ xtables_save_main(int family, int argc, char *argv[], return 1; } - if (nft_init(&h, family, tables) < 0) { + if (nft_init(&h, family) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 1a6b7cf7..f4d40cda 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -60,7 +60,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) init_extensions6(); #endif - if (nft_init(&h, family, xtables_ipv4) < 0) { + if (nft_init(&h, family) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 2a00a850..086b85d2 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -465,7 +465,6 @@ static int xtables_xlate_main_common(struct nft_handle *h, int family, const char *progname) { - const struct builtin_table *tables; int ret; xtables_globals.program_name = progname; @@ -485,20 +484,16 @@ static int xtables_xlate_main_common(struct nft_handle *h, init_extensions4(); init_extensions6(); #endif - tables = xtables_ipv4; break; case NFPROTO_ARP: - tables = xtables_arp; - break; case NFPROTO_BRIDGE: - tables = xtables_bridge; break; default: fprintf(stderr, "Unknown family %d\n", family); return 1; } - if (nft_init(h, family, tables) < 0) { + if (nft_init(h, family) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, -- cgit v1.2.3 From 65b150ae382a8b5d1fc7f2465b3ac590c1601ce1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: xshared: Store optstring in xtables_globals Preparing for a common option parser, store the string of options for each family inside the respective xtables_globals object. The array of long option definitions sitting in there already indicates it's the right place. While being at it, drop '-m' support from arptables-nft. Signed-off-by: Phil Sutter --- include/xtables.h | 1 + iptables/xshared.h | 2 ++ iptables/xtables-arp.c | 4 ++-- iptables/xtables-eb.c | 5 +++-- iptables/xtables.c | 4 ++-- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index e51f4bfd..c872a042 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -420,6 +420,7 @@ struct xtables_globals { unsigned int option_offset; const char *program_name, *program_version; + const char *optstring; struct option *orig_opts; struct option *opts; void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); diff --git a/iptables/xshared.h b/iptables/xshared.h index 823894f9..b59116ac 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -68,6 +68,8 @@ struct xtables_globals; struct xtables_rule_match; struct xtables_target; +#define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:VX::Z::" "c:d:i:j:o:p:s:t:" + /* define invflags which won't collide with IPT ones */ #define IPT_INV_SRCDEVADDR 0x0080 #define IPT_INV_TGTDEVADDR 0x0100 diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 1d132bdf..a028ac34 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -100,6 +100,7 @@ extern void xtables_exit_error(enum xtables_exittype status, const char *msg, .. struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION, + .optstring = OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, @@ -444,8 +445,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, opterr = 0; opts = xt_params->orig_opts; - while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:", + while ((c = getopt_long(argc, argv, xt_params->optstring, opts, NULL)) != -1) { switch (c) { /* diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 1ed6bcd8..3f58754d 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -220,6 +220,7 @@ extern void xtables_exit_error(enum xtables_exittype status, const char *msg, .. struct xtables_globals ebtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION, + .optstring = OPTSTRING_COMMON "h", .orig_opts = ebt_original_options, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, @@ -732,8 +733,8 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, opterr = false; /* Getopt saves the day */ - while ((c = getopt_long(argc, argv, - "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, xt_params->optstring, + opts, NULL)) != -1) { cs.c = c; switch (c) { diff --git a/iptables/xtables.c b/iptables/xtables.c index 0a700e08..c17cf7ae 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -89,6 +89,7 @@ void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __at struct xtables_globals xtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION, + .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, @@ -455,8 +456,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], opterr = 0; opts = xt_params->orig_opts; - while ((cs->c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46", + while ((cs->c = getopt_long(argc, argv, xt_params->optstring, opts, NULL)) != -1) { switch (cs->c) { /* -- cgit v1.2.3 From cfdda18044d81ca2e8a4f9df8a518290e2e94a07 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft-shared: Introduce init_cs family ops callback Arptables sets a few defaults in struct iptables_command_state upon initialization. Introduce a callback to do that. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 9 +++++++++ iptables/nft-shared.h | 1 + iptables/xtables.c | 12 +++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 2a9387a1..fbaf1a6d 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -546,6 +546,14 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy) printf(":%s %s\n", chain, policy ?: "-"); } +static void nft_arp_init_cs(struct iptables_command_state *cs) +{ + cs->arp.arp.arhln = 6; + cs->arp.arp.arhln_mask = 255; + cs->arp.arp.arhrd = htons(ARPHRD_ETHER); + cs->arp.arp.arhrd_mask = 65535; +} + struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, @@ -559,6 +567,7 @@ struct nft_family_ops nft_family_ops_arp = { .save_chain = nft_arp_save_chain, .post_parse = NULL, .rule_to_cs = nft_rule_to_iptables_command_state, + .init_cs = nft_arp_init_cs, .clear_cs = nft_clear_iptables_command_state, .parse_target = nft_ipv46_parse_target, }; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index cc8f3a79..71094a28 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -106,6 +106,7 @@ struct nft_family_ops { struct xtables_args *args); void (*parse_match)(struct xtables_match *m, void *data); void (*parse_target)(struct xtables_target *t, void *data); + void (*init_cs)(struct iptables_command_state *cs); void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); diff --git a/iptables/xtables.c b/iptables/xtables.c index c17cf7ae..092edaaf 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -433,10 +433,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], bool invert = false; int wait = 0; - memset(cs, 0, sizeof(*cs)); - cs->jumpto = ""; - cs->argv = argv; - /* re-set optind to 0 in case do_command4 gets called * a second time */ optind = 0; @@ -912,11 +908,17 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, .table = *table, .restore = restore, }; - struct iptables_command_state cs; + struct iptables_command_state cs = { + .jumpto = "", + .argv = argv, + }; struct xtables_args args = { .family = h->family, }; + if (h->ops->init_cs) + h->ops->init_cs(&cs); + do_parse(h, argc, argv, &p, &cs, &args); switch (p.command) { -- cgit v1.2.3 From 38e1fe58fe814e4364155085327c0b1e2d9527ee Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: xtables: Simplify addr_mask freeing Introduce a generic 'ptr' union field to pass to free(). Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 2 ++ iptables/xtables.c | 15 ++++----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 71094a28..44ad0811 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -177,6 +177,7 @@ struct addr_mask { union { struct in_addr *v4; struct in6_addr *v6; + void *ptr; } addr; unsigned int naddrs; @@ -184,6 +185,7 @@ struct addr_mask { union { struct in_addr *v4; struct in6_addr *v6; + void *ptr; } mask; }; diff --git a/iptables/xtables.c b/iptables/xtables.c index 092edaaf..f45e3608 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -1021,17 +1021,10 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, nft_clear_iptables_command_state(&cs); - if (h->family == AF_INET) { - free(args.s.addr.v4); - free(args.s.mask.v4); - free(args.d.addr.v4); - free(args.d.mask.v4); - } else if (h->family == AF_INET6) { - free(args.s.addr.v6); - free(args.s.mask.v6); - free(args.d.addr.v6); - free(args.d.mask.v6); - } + free(args.s.addr.ptr); + free(args.s.mask.ptr); + free(args.d.addr.ptr); + free(args.d.mask.ptr); xtables_free_opts(1); return ret; -- cgit v1.2.3 From dded8ff3878ba7dccb8573543f2c2c5c8670fa03 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft: Add family ops callbacks wrapping different nft_cmd_* functions Commands supporting multiple source/destination addresses need to iterate over them and call the respective nft_cmd_* function multiple times. These loops are family-specific though as each family uses a different data structure within struct iptables_command_state to store the addresses. Signed-off-by: Phil Sutter --- iptables/nft-ipv4.c | 93 ++++++++++++++++++++++++ iptables/nft-ipv6.c | 104 +++++++++++++++++++++++++++ iptables/nft-shared.h | 18 +++++ iptables/xtables.c | 190 ++++---------------------------------------------- 4 files changed, 228 insertions(+), 177 deletions(-) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 34f94bd8..febd7673 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -468,6 +468,95 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl) return ret; } +static int +nft_ipv4_add_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr; + cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr; + cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr; + + if (append) { + ret = nft_cmd_rule_append(h, chain, table, + cs, NULL, verbose); + } else { + ret = nft_cmd_rule_insert(h, chain, table, + cs, rulenum, verbose); + } + } + } + + return ret; +} + +static int +nft_ipv4_delete_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr; + cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr; + cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_ipv4_check_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr; + cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr; + cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_check(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_ipv4_replace_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum) +{ + cs->fw.ip.src.s_addr = args->s.addr.v4->s_addr; + cs->fw.ip.dst.s_addr = args->d.addr.v4->s_addr; + cs->fw.ip.smsk.s_addr = args->s.mask.v4->s_addr; + cs->fw.ip.dmsk.s_addr = args->d.mask.v4->s_addr; + + return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); +} + struct nft_family_ops nft_family_ops_ipv4 = { .add = nft_ipv4_add, .is_same = nft_ipv4_is_same, @@ -484,4 +573,8 @@ struct nft_family_ops nft_family_ops_ipv4 = { .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = nft_clear_iptables_command_state, .xlate = nft_ipv4_xlate, + .add_entry = nft_ipv4_add_entry, + .delete_entry = nft_ipv4_delete_entry, + .check_entry = nft_ipv4_check_entry, + .replace_entry = nft_ipv4_replace_entry, }; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index d9c9400a..f0e64bbd 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -410,6 +410,106 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl) return ret; } +static int +nft_ipv6_add_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + memcpy(&cs->fw6.ipv6.src, + &args->s.addr.v6[i], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.smsk, + &args->s.mask.v6[i], sizeof(struct in6_addr)); + for (j = 0; j < args->d.naddrs; j++) { + memcpy(&cs->fw6.ipv6.dst, + &args->d.addr.v6[j], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.dmsk, + &args->d.mask.v6[j], sizeof(struct in6_addr)); + if (append) { + ret = nft_cmd_rule_append(h, chain, table, + cs, NULL, verbose); + } else { + ret = nft_cmd_rule_insert(h, chain, table, + cs, rulenum, verbose); + } + } + } + + return ret; +} + +static int +nft_ipv6_delete_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + memcpy(&cs->fw6.ipv6.src, + &args->s.addr.v6[i], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.smsk, + &args->s.mask.v6[i], sizeof(struct in6_addr)); + for (j = 0; j < args->d.naddrs; j++) { + memcpy(&cs->fw6.ipv6.dst, + &args->d.addr.v6[j], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.dmsk, + &args->d.mask.v6[j], sizeof(struct in6_addr)); + ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_ipv6_check_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + memcpy(&cs->fw6.ipv6.src, + &args->s.addr.v6[i], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.smsk, + &args->s.mask.v6[i], sizeof(struct in6_addr)); + for (j = 0; j < args->d.naddrs; j++) { + memcpy(&cs->fw6.ipv6.dst, + &args->d.addr.v6[j], sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.dmsk, + &args->d.mask.v6[j], sizeof(struct in6_addr)); + ret = nft_cmd_rule_check(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_ipv6_replace_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum) +{ + memcpy(&cs->fw6.ipv6.src, args->s.addr.v6, sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.dst, args->d.addr.v6, sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.smsk, args->s.mask.v6, sizeof(struct in6_addr)); + memcpy(&cs->fw6.ipv6.dmsk, args->d.mask.v6, sizeof(struct in6_addr)); + + return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); +} + struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, @@ -426,4 +526,8 @@ struct nft_family_ops nft_family_ops_ipv6 = { .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = nft_clear_iptables_command_state, .xlate = nft_ipv6_xlate, + .add_entry = nft_ipv6_add_entry, + .delete_entry = nft_ipv6_delete_entry, + .check_entry = nft_ipv6_check_entry, + .replace_entry = nft_ipv6_replace_entry, }; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 44ad0811..cb1c3fff 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -111,6 +111,24 @@ struct nft_family_ops { struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); int (*xlate)(const void *data, struct xt_xlate *xl); + int (*add_entry)(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum); + int (*delete_entry)(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose); + int (*check_entry)(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose); + int (*replace_entry)(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum); }; void add_meta(struct nftnl_rule *r, uint32_t key); diff --git a/iptables/xtables.c b/iptables/xtables.c index f45e3608..9abfc8f8 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -223,168 +223,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static int -add_entry(const char *chain, - const char *table, - struct iptables_command_state *cs, - int rulenum, int family, - const struct addr_mask s, - const struct addr_mask d, - bool verbose, struct nft_handle *h, bool append) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < s.naddrs; i++) { - if (family == AF_INET) { - cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr; - cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr; - for (j = 0; j < d.naddrs; j++) { - cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr; - cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr; - - if (append) { - ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, - verbose); - } else { - ret = nft_cmd_rule_insert(h, chain, table, - cs, rulenum, - verbose); - } - } - } else if (family == AF_INET6) { - memcpy(&cs->fw6.ipv6.src, - &s.addr.v6[i], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.smsk, - &s.mask.v6[i], sizeof(struct in6_addr)); - for (j = 0; j < d.naddrs; j++) { - memcpy(&cs->fw6.ipv6.dst, - &d.addr.v6[j], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.dmsk, - &d.mask.v6[j], sizeof(struct in6_addr)); - if (append) { - ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, - verbose); - } else { - ret = nft_cmd_rule_insert(h, chain, table, - cs, rulenum, - verbose); - } - } - } - } - - return ret; -} - -static int -replace_entry(const char *chain, const char *table, - struct iptables_command_state *cs, - unsigned int rulenum, - int family, - const struct addr_mask s, - const struct addr_mask d, - bool verbose, struct nft_handle *h) -{ - if (family == AF_INET) { - cs->fw.ip.src.s_addr = s.addr.v4->s_addr; - cs->fw.ip.dst.s_addr = d.addr.v4->s_addr; - cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr; - cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr; - } else if (family == AF_INET6) { - memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr)); - } else - return 1; - - return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); -} - -static int -delete_entry(const char *chain, const char *table, - struct iptables_command_state *cs, - int family, - const struct addr_mask s, - const struct addr_mask d, - bool verbose, - struct nft_handle *h) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < s.naddrs; i++) { - if (family == AF_INET) { - cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr; - cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr; - for (j = 0; j < d.naddrs; j++) { - cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr; - cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr; - ret = nft_cmd_rule_delete(h, chain, - table, cs, verbose); - } - } else if (family == AF_INET6) { - memcpy(&cs->fw6.ipv6.src, - &s.addr.v6[i], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.smsk, - &s.mask.v6[i], sizeof(struct in6_addr)); - for (j = 0; j < d.naddrs; j++) { - memcpy(&cs->fw6.ipv6.dst, - &d.addr.v6[j], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.dmsk, - &d.mask.v6[j], sizeof(struct in6_addr)); - ret = nft_cmd_rule_delete(h, chain, - table, cs, verbose); - } - } - } - - return ret; -} - -static int -check_entry(const char *chain, const char *table, - struct iptables_command_state *cs, - int family, - const struct addr_mask s, - const struct addr_mask d, - bool verbose, struct nft_handle *h) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < s.naddrs; i++) { - if (family == AF_INET) { - cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr; - cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr; - for (j = 0; j < d.naddrs; j++) { - cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr; - cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr; - ret = nft_cmd_rule_check(h, chain, - table, cs, verbose); - } - } else if (family == AF_INET6) { - memcpy(&cs->fw6.ipv6.src, - &s.addr.v6[i], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.smsk, - &s.mask.v6[i], sizeof(struct in6_addr)); - for (j = 0; j < d.naddrs; j++) { - memcpy(&cs->fw6.ipv6.dst, - &d.addr.v6[j], sizeof(struct in6_addr)); - memcpy(&cs->fw6.ipv6.dmsk, - &d.mask.v6[j], sizeof(struct in6_addr)); - ret = nft_cmd_rule_check(h, chain, - table, cs, verbose); - } - } - } - - return ret; -} - static int list_entries(struct nft_handle *h, const char *chain, const char *table, int rulenum, int verbose, int numeric, int expanded, @@ -923,33 +761,31 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, switch (p.command) { case CMD_APPEND: - ret = add_entry(p.chain, p.table, &cs, 0, h->family, - args.s, args.d, - cs.options & OPT_VERBOSE, h, true); + ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args, + cs.options & OPT_VERBOSE, true, + p.rulenum - 1); break; case CMD_DELETE: - ret = delete_entry(p.chain, p.table, &cs, h->family, - args.s, args.d, - cs.options & OPT_VERBOSE, h); + ret = h->ops->delete_entry(h, p.chain, p.table, &cs, &args, + cs.options & OPT_VERBOSE); break; case CMD_DELETE_NUM: ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose); break; case CMD_CHECK: - ret = check_entry(p.chain, p.table, &cs, h->family, - args.s, args.d, - cs.options & OPT_VERBOSE, h); + ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args, + cs.options & OPT_VERBOSE); break; case CMD_REPLACE: - ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1, - h->family, args.s, args.d, - cs.options & OPT_VERBOSE, h); + ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args, + cs.options & OPT_VERBOSE, + p.rulenum - 1); break; case CMD_INSERT: - ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1, - h->family, args.s, args.d, - cs.options&OPT_VERBOSE, h, false); + ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args, + cs.options & OPT_VERBOSE, false, + p.rulenum - 1); break; case CMD_FLUSH: ret = nft_cmd_rule_flush(h, p.chain, p.table, -- cgit v1.2.3 From 0687852da7ed0a7ec8ebc88b41031dcae18c8898 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: xtables-standalone: Drop version number from init errors Aside from the rather unconventional formatting, if those initialization functions fail we've either released a completely broken iptables or the wrong libraries are chosen by the loader. In both cases, the version number is not really interesting. While being at it, fix indenting of the first exit() call. Signed-off-by: Phil Sutter --- iptables/xtables-standalone.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index f4d40cda..54c70c54 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -49,10 +49,8 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) xtables_globals.program_name = progname; ret = xtables_init_all(&xtables_globals, family); if (ret < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - xtables_globals.program_name, - xtables_globals.program_version); - exit(1); + fprintf(stderr, "%s: Failed to initialize xtables\n", progname); + exit(1); } #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); @@ -61,10 +59,8 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) #endif if (nft_init(&h, family) < 0) { - fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", - xtables_globals.program_name, - xtables_globals.program_version, - strerror(errno)); + fprintf(stderr, "%s: Failed to initialize nft: %s\n", + xtables_globals.program_name, strerror(errno)); exit(EXIT_FAILURE); } -- cgit v1.2.3 From fe83b12fc910e43e4f22a25b56210b0dd0afc3ee Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: libxtables: Introduce xtables_globals print_help callback With optstring being stored in struct xtables_globals as well, it is a natural choice to store a pointer to a help printer also which matches the supported options. Signed-off-by: Phil Sutter --- include/xtables.h | 1 + iptables/xtables-arp.c | 6 ++++-- iptables/xtables.c | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index c872a042..ca674c26 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -425,6 +425,7 @@ struct xtables_globals struct option *opts; void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); int (*compat_rev)(const char *name, uint8_t rev, int opt); + void (*print_help)(const struct xtables_rule_match *m); }; #define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false} diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index a028ac34..2e4bb3f2 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -97,6 +97,7 @@ static struct option original_opts[] = { #define opts xt_params->opts extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); +static void printhelp(const struct xtables_rule_match *m); struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION, @@ -104,6 +105,7 @@ struct xtables_globals arptables_globals = { .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, + .print_help = printhelp, }; /***********************************************/ @@ -164,7 +166,7 @@ exit_tryhelp(int status) } static void -printhelp(void) +printhelp(const struct xtables_rule_match *m) { struct xtables_target *t = NULL; int i; @@ -563,7 +565,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, if (!optarg) optarg = argv[optind]; - printhelp(); + xt_params->print_help(NULL); command = CMD_NONE; break; case 's': diff --git a/iptables/xtables.c b/iptables/xtables.c index 9abfc8f8..2b3cc930 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -85,6 +85,7 @@ static struct option original_opts[] = { }; void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); +static void printhelp(const struct xtables_rule_match *m); struct xtables_globals xtables_globals = { .option_offset = 0, @@ -93,6 +94,7 @@ struct xtables_globals xtables_globals = { .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, + .print_help = printhelp, }; #define opts xt_params->opts @@ -435,7 +437,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], xtables_find_match(cs->protocol, XTF_TRY_LOAD, &cs->matches); - printhelp(cs->matches); + xt_params->print_help(cs->matches); p->command = CMD_NONE; return; -- cgit v1.2.3 From 0aea399d2cccd9f1e92380d3ec27edc9b455e1e7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: arptables: Use standard data structures when parsing Use the compound data structures introduced for dedicated parsing routines in other families instead of the many local variables. This allows to standardize code a bit for sharing a common parser later. Signed-off-by: Phil Sutter --- iptables/xtables-arp.c | 280 ++++++++++++++++++++++++------------------------- 1 file changed, 138 insertions(+), 142 deletions(-) diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 2e4bb3f2..1075b6be 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -419,17 +419,13 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, .arhrd_mask = 65535, }, }; + struct nft_xt_cmd_parse p = { + .table = *table, + }; + struct xtables_args args = { + .family = h->family, + }; int invert = 0; - unsigned int nsaddrs = 0, ndaddrs = 0; - struct in_addr *saddrs = NULL, *smasks = NULL; - struct in_addr *daddrs = NULL, *dmasks = NULL; - - int c, verbose = 0; - const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; - const char *policy = NULL, *newname = NULL; - unsigned int rulenum = 0, options = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; int ret = 1; struct xtables_target *t; @@ -447,34 +443,34 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, opterr = 0; opts = xt_params->orig_opts; - while ((c = getopt_long(argc, argv, xt_params->optstring, + while ((cs.c = getopt_long(argc, argv, xt_params->optstring, opts, NULL)) != -1) { - switch (c) { + switch (cs.c) { /* * Command selection */ case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, + add_command(&p.command, CMD_APPEND, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; break; case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, + add_command(&p.command, CMD_DELETE, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; + p.rulenum = parse_rulenumber(argv[optind++]); + p.command = CMD_DELETE_NUM; } break; case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, + add_command(&p.command, CMD_REPLACE, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); + p.rulenum = parse_rulenumber(argv[optind++]); else xtables_error(PARAMETER_PROBLEM, "-%c requires a rule number", @@ -482,36 +478,36 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, break; case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, + add_command(&p.command, CMD_INSERT, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; + p.rulenum = parse_rulenumber(argv[optind++]); + else p.rulenum = 1; break; case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, + add_command(&p.command, CMD_LIST, CMD_ZERO, invert); - if (optarg) chain = optarg; + if (optarg) p.chain = optarg; else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; + p.chain = argv[optind++]; break; case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, + add_command(&p.command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) chain = optarg; + if (optarg) p.chain = optarg; else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; + p.chain = argv[optind++]; break; case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, + add_command(&p.command, CMD_ZERO, CMD_LIST, invert); - if (optarg) chain = optarg; + if (optarg) p.chain = optarg; else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; + p.chain = argv[optind++]; break; case 'N': @@ -523,25 +519,25 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "chain name may not clash " "with target name\n"); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, + add_command(&p.command, CMD_NEW_CHAIN, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; break; case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, + add_command(&p.command, CMD_DELETE_CHAIN, CMD_NONE, invert); - if (optarg) chain = optarg; + if (optarg) p.chain = optarg; else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; + p.chain = argv[optind++]; break; case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, + add_command(&p.command, CMD_RENAME_CHAIN, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; if (xs_has_arg(argc, argv)) - newname = argv[optind++]; + p.newname = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires old-chain-name and " @@ -550,11 +546,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, break; case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, + add_command(&p.command, CMD_SET_POLICY, CMD_NONE, invert); - chain = optarg; + p.chain = optarg; if (xs_has_arg(argc, argv)) - policy = argv[optind++]; + p.policy = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires a chain and a policy", @@ -566,25 +562,25 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, optarg = argv[optind]; xt_params->print_help(NULL); - command = CMD_NONE; + p.command = CMD_NONE; break; case 's': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_SOURCE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_SOURCE, &cs.arp.arp.invflags, invert); - shostnetworkmask = argv[optind-1]; + args.shostnetworkmask = argv[optind-1]; break; case 'd': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_DESTINATION, &cs.arp.arp.invflags, invert); - dhostnetworkmask = argv[optind-1]; + args.dhostnetworkmask = argv[optind-1]; break; case 2:/* src-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_S_MAC, &cs.arp.arp.invflags, invert); if (xtables_parse_mac_and_mask(argv[optind - 1], cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask)) @@ -594,7 +590,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 3:/* dst-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_D_MAC, &cs.arp.arp.invflags, invert); if (xtables_parse_mac_and_mask(argv[optind - 1], @@ -605,7 +601,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 'l':/* hardware length */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_H_LENGTH, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_H_LENGTH, &cs.arp.arp.invflags, invert); getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln, &cs.arp.arp.arhln_mask); @@ -622,7 +618,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "not supported"); case 4:/* opcode */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_OPCODE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_OPCODE, &cs.arp.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop, &cs.arp.arp.arpop_mask, 10)) { @@ -639,7 +635,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 5:/* h-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_H_TYPE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_H_TYPE, &cs.arp.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd, &cs.arp.arp.arhrd_mask, 16)) { @@ -651,7 +647,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 6:/* proto-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_P_TYPE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_P_TYPE, &cs.arp.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro, &cs.arp.arp.arpro_mask, 0)) { @@ -662,14 +658,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, break; case 'j': - set_option(&options, OPT_JUMP, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_JUMP, &cs.arp.arp.invflags, invert); command_jump(&cs, optarg); break; case 'i': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_VIANAMEIN, &cs.arp.arp.invflags, invert); xtables_parse_interface(argv[optind-1], cs.arp.arp.iniface, @@ -678,7 +674,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 'o': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_VIANAMEOUT, &cs.arp.arp.invflags, invert); xtables_parse_interface(argv[optind-1], cs.arp.arp.outiface, @@ -686,16 +682,16 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, break; case 'v': - if (!verbose) - set_option(&options, OPT_VERBOSE, + if (!p.verbose) + set_option(&cs.options, OPT_VERBOSE, &cs.arp.arp.invflags, invert); - verbose++; + p.verbose++; break; case 'm': /* ignored by arptables-legacy */ break; case 'n': - set_option(&options, OPT_NUMERIC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_NUMERIC, &cs.arp.arp.invflags, invert); break; @@ -719,7 +715,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, exit(0); case '0': - set_option(&options, OPT_LINENUMBERS, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_LINENUMBERS, &cs.arp.arp.invflags, invert); break; @@ -729,22 +725,22 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 'c': - set_option(&options, OPT_COUNTERS, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_COUNTERS, &cs.arp.arp.invflags, invert); - pcnt = optarg; + args.pcnt = optarg; if (xs_has_arg(argc, argv)) - bcnt = argv[optind++]; + args.bcnt = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); - if (sscanf(pcnt, "%llu", &cs.arp.counters.pcnt) != 1) + if (sscanf(args.pcnt, "%llu", &cs.arp.counters.pcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); - if (sscanf(bcnt, "%llu", &cs.arp.counters.bcnt) != 1) + if (sscanf(args.bcnt, "%llu", &cs.arp.counters.bcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); @@ -767,7 +763,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, default: if (cs.target) { - xtables_option_tpcall(c, argv, + xtables_option_tpcall(cs.c, argv, invert, cs.target, &cs.arp); } break; @@ -785,127 +781,127 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; + if (p.command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { + if (!(cs.options & OPT_DESTINATION)) + args.dhostnetworkmask = "0.0.0.0/0"; + if (!(cs.options & OPT_SOURCE)) + args.shostnetworkmask = "0.0.0.0/0"; } - if (shostnetworkmask) - xtables_ipparse_multiple(shostnetworkmask, &saddrs, - &smasks, &nsaddrs); + if (args.shostnetworkmask) + xtables_ipparse_multiple(args.shostnetworkmask, &args.s.addr.v4, + &args.s.mask.v4, &args.s.naddrs); - if (dhostnetworkmask) - xtables_ipparse_multiple(dhostnetworkmask, &daddrs, - &dmasks, &ndaddrs); + if (args.dhostnetworkmask) + xtables_ipparse_multiple(args.dhostnetworkmask, &args.d.addr.v4, + &args.d.mask.v4, &args.d.naddrs); - if ((nsaddrs > 1 || ndaddrs > 1) && + if ((args.s.naddrs > 1 || args.d.naddrs > 1) && (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); - if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) + if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1)) xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); - if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN) + if (p.chain && strlen(p.chain) > ARPT_FUNCTION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "chain name `%s' too long (must be under %i chars)", - chain, ARPT_FUNCTION_MAXNAMELEN); - - if (command == CMD_APPEND - || command == CMD_DELETE - || command == CMD_INSERT - || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { + p.chain, ARPT_FUNCTION_MAXNAMELEN); + + if (p.command == CMD_APPEND + || p.command == CMD_DELETE + || p.command == CMD_INSERT + || p.command == CMD_REPLACE) { + if (strcmp(p.chain, "PREROUTING") == 0 + || strcmp(p.chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) + if (cs.options & OPT_VIANAMEOUT) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), - chain); + p.chain); } - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { + if (strcmp(p.chain, "POSTROUTING") == 0 + || strcmp(p.chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) + if (cs.options & OPT_VIANAMEIN) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), - chain); + p.chain); } } - switch (command) { + switch (p.command) { case CMD_APPEND: - ret = append_entry(h, chain, *table, &cs, 0, - nsaddrs, saddrs, smasks, - ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, true); + ret = append_entry(h, p.chain, p.table, &cs, 0, + args.s.naddrs, args.s.addr.v4, args.s.mask.v4, + args.d.naddrs, args.d.addr.v4, args.d.mask.v4, + cs.options&OPT_VERBOSE, true); break; case CMD_DELETE: - ret = delete_entry(chain, *table, &cs, - nsaddrs, saddrs, smasks, - ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, h); + ret = delete_entry(p.chain, p.table, &cs, + args.s.naddrs, args.s.addr.v4, args.s.mask.v4, + args.d.naddrs, args.d.addr.v4, args.d.mask.v4, + cs.options&OPT_VERBOSE, h); break; case CMD_DELETE_NUM: - ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose); + ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose); break; case CMD_REPLACE: - ret = replace_entry(chain, *table, &cs, rulenum - 1, - saddrs, smasks, daddrs, dmasks, - options&OPT_VERBOSE, h); + ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1, + args.s.addr.v4, args.s.mask.v4, args.d.addr.v4, args.d.mask.v4, + cs.options&OPT_VERBOSE, h); break; case CMD_INSERT: - ret = append_entry(h, chain, *table, &cs, rulenum - 1, - nsaddrs, saddrs, smasks, - ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, false); + ret = append_entry(h, p.chain, p.table, &cs, p.rulenum - 1, + args.s.naddrs, args.s.addr.v4, args.s.mask.v4, + args.d.naddrs, args.d.addr.v4, args.d.mask.v4, + cs.options&OPT_VERBOSE, false); break; case CMD_LIST: - ret = list_entries(h, chain, *table, - rulenum, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - /*options&OPT_EXPANDED*/0, - options&OPT_LINENUMBERS); + ret = list_entries(h, p.chain, p.table, + p.rulenum, + cs.options&OPT_VERBOSE, + cs.options&OPT_NUMERIC, + /*cs.options&OPT_EXPANDED*/0, + cs.options&OPT_LINENUMBERS); break; case CMD_FLUSH: - ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE); + ret = nft_cmd_rule_flush(h, p.chain, p.table, cs.options & OPT_VERBOSE); break; case CMD_ZERO: - ret = nft_cmd_chain_zero_counters(h, chain, *table, - options & OPT_VERBOSE); + ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, + cs.options & OPT_VERBOSE); break; case CMD_LIST|CMD_ZERO: - ret = list_entries(h, chain, *table, rulenum, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - /*options&OPT_EXPANDED*/0, - options&OPT_LINENUMBERS); + ret = list_entries(h, p.chain, p.table, p.rulenum, + cs.options&OPT_VERBOSE, + cs.options&OPT_NUMERIC, + /*cs.options&OPT_EXPANDED*/0, + cs.options&OPT_LINENUMBERS); if (ret) - ret = nft_cmd_chain_zero_counters(h, chain, *table, - options & OPT_VERBOSE); + ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, + cs.options & OPT_VERBOSE); break; case CMD_NEW_CHAIN: - ret = nft_cmd_chain_user_add(h, chain, *table); + ret = nft_cmd_chain_user_add(h, p.chain, p.table); break; case CMD_DELETE_CHAIN: - ret = nft_cmd_chain_del(h, chain, *table, - options & OPT_VERBOSE); + ret = nft_cmd_chain_del(h, p.chain, p.table, + cs.options & OPT_VERBOSE); break; case CMD_RENAME_CHAIN: - ret = nft_cmd_chain_user_rename(h, chain, *table, newname); + ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname); break; case CMD_SET_POLICY: - ret = nft_cmd_chain_set(h, *table, chain, policy, NULL); + ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL); if (ret < 0) xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n", - policy); + p.policy); break; case CMD_NONE: break; @@ -914,15 +910,15 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, exit_tryhelp(2); } - free(saddrs); - free(smasks); - free(daddrs); - free(dmasks); + free(args.s.addr.v4); + free(args.s.mask.v4); + free(args.d.addr.v4); + free(args.d.mask.v4); nft_clear_iptables_command_state(&cs); xtables_free_opts(1); -/* if (verbose > 1) +/* if (p.verbose > 1) dump_entries(*handle);*/ return ret; -- cgit v1.2.3 From 832a0e2b838546f4266094fae29dd54c6cdeeb82 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft-arp: Introduce post_parse callback This accomplishes the same tasks as e.g. nft_ipv4_post_parse() plus some arptables-specific bits. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++- iptables/nft-shared.h | 3 + iptables/xtables-arp.c | 153 +++++++++---------------------------------------- 3 files changed, 178 insertions(+), 128 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index fbaf1a6d..b37ffbb5 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -546,6 +546,154 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy) printf(":%s %s\n", chain, policy ?: "-"); } +static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask) +{ + char *dup = strdup(from); + char *p, *buffer; + int i, ret = -1; + + if (!dup) + return -1; + + if ( (p = strrchr(dup, '/')) != NULL) { + *p = '\0'; + i = strtol(p+1, &buffer, 10); + if (*buffer != '\0' || i < 0 || i > 255) + goto out_err; + *mask = (uint8_t)i; + } else + *mask = 255; + i = strtol(dup, &buffer, 10); + if (*buffer != '\0' || i < 0 || i > 255) + goto out_err; + *to = (uint8_t)i; + ret = 0; +out_err: + free(dup); + return ret; + +} + +static int get16_and_mask(const char *from, uint16_t *to, + uint16_t *mask, int base) +{ + char *dup = strdup(from); + char *p, *buffer; + int i, ret = -1; + + if (!dup) + return -1; + + if ( (p = strrchr(dup, '/')) != NULL) { + *p = '\0'; + i = strtol(p+1, &buffer, base); + if (*buffer != '\0' || i < 0 || i > 65535) + goto out_err; + *mask = htons((uint16_t)i); + } else + *mask = 65535; + i = strtol(dup, &buffer, base); + if (*buffer != '\0' || i < 0 || i > 65535) + goto out_err; + *to = htons((uint16_t)i); + ret = 0; +out_err: + free(dup); + return ret; +} + +static void nft_arp_post_parse(int command, + struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->arp.arp.invflags = args->invflags; + + memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ); + + memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ); + + cs->arp.counters.pcnt = args->pcnt_cnt; + cs->arp.counters.bcnt = args->bcnt_cnt; + + if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { + if (!(cs->options & OPT_DESTINATION)) + args->dhostnetworkmask = "0.0.0.0/0"; + if (!(cs->options & OPT_SOURCE)) + args->shostnetworkmask = "0.0.0.0/0"; + } + + if (args->shostnetworkmask) + xtables_ipparse_multiple(args->shostnetworkmask, + &args->s.addr.v4, &args->s.mask.v4, + &args->s.naddrs); + if (args->dhostnetworkmask) + xtables_ipparse_multiple(args->dhostnetworkmask, + &args->d.addr.v4, &args->d.mask.v4, + &args->d.naddrs); + + if ((args->s.naddrs > 1 || args->d.naddrs > 1) && + (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) + xtables_error(PARAMETER_PROBLEM, + "! not allowed with multiple" + " source or destination IP addresses"); + + if (args->src_mac && + xtables_parse_mac_and_mask(args->src_mac, + cs->arp.arp.src_devaddr.addr, + cs->arp.arp.src_devaddr.mask)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified source mac"); + if (args->dst_mac && + xtables_parse_mac_and_mask(args->dst_mac, + cs->arp.arp.tgt_devaddr.addr, + cs->arp.arp.tgt_devaddr.mask)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified destination mac"); + if (args->arp_hlen) { + getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln, + &cs->arp.arp.arhln_mask); + + if (cs->arp.arp.arhln != 6) + xtables_error(PARAMETER_PROBLEM, + "Only harware address length of 6 is supported currently."); + } + if (args->arp_opcode) { + if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop, + &cs->arp.arp.arpop_mask, 10)) { + int i; + + for (i = 0; i < NUMOPCODES; i++) + if (!strcasecmp(arp_opcodes[i], + args->arp_opcode)) + break; + if (i == NUMOPCODES) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified opcode"); + cs->arp.arp.arpop = htons(i+1); + } + } + if (args->arp_htype) { + if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd, + &cs->arp.arp.arhrd_mask, 16)) { + if (strcasecmp(args->arp_htype, "Ethernet")) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified hardware type"); + cs->arp.arp.arhrd = htons(1); + } + } + if (args->arp_ptype) { + if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro, + &cs->arp.arp.arpro_mask, 0)) { + if (strcasecmp(args->arp_ptype, "ipv4")) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified protocol type"); + cs->arp.arp.arpro = htons(0x800); + } + } +} + static void nft_arp_init_cs(struct iptables_command_state *cs) { cs->arp.arp.arhln = 6; @@ -565,7 +713,7 @@ struct nft_family_ops nft_family_ops_arp = { .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, - .post_parse = NULL, + .post_parse = nft_arp_post_parse, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, .clear_cs = nft_clear_iptables_command_state, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index cb1c3fff..339c46e7 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -218,6 +218,9 @@ struct xtables_args { const char *shostnetworkmask, *dhostnetworkmask; const char *pcnt, *bcnt; struct addr_mask s, d; + const char *src_mac, *dst_mac; + const char *arp_hlen, *arp_opcode; + const char *arp_htype, *arp_ptype; unsigned long long pcnt_cnt, bcnt_cnt; }; diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 1075b6be..de7c3817 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -108,54 +108,6 @@ struct xtables_globals arptables_globals = { .print_help = printhelp, }; -/***********************************************/ -/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */ -/***********************************************/ - -static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask) -{ - char *p, *buffer; - int i; - - if ( (p = strrchr(from, '/')) != NULL) { - *p = '\0'; - i = strtol(p+1, &buffer, 10); - if (*buffer != '\0' || i < 0 || i > 255) - return -1; - *mask = (uint8_t)i; - } else - *mask = 255; - i = strtol(from, &buffer, 10); - if (*buffer != '\0' || i < 0 || i > 255) - return -1; - *to = (uint8_t)i; - return 0; -} - -static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base) -{ - char *p, *buffer; - int i; - - if ( (p = strrchr(from, '/')) != NULL) { - *p = '\0'; - i = strtol(p+1, &buffer, base); - if (*buffer != '\0' || i < 0 || i > 65535) - return -1; - *mask = htons((uint16_t)i); - } else - *mask = 65535; - i = strtol(from, &buffer, base); - if (*buffer != '\0' || i < 0 || i > 65535) - return -1; - *to = htons((uint16_t)i); - return 0; -} - -/*********************************************/ -/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */ -/*********************************************/ - static void exit_tryhelp(int status) { @@ -566,132 +518,97 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, break; case 's': check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_SOURCE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_SOURCE, &args.invflags, invert); args.shostnetworkmask = argv[optind-1]; break; case 'd': check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_DESTINATION, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_DESTINATION, &args.invflags, invert); args.dhostnetworkmask = argv[optind-1]; break; case 2:/* src-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_S_MAC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_S_MAC, &args.invflags, invert); - if (xtables_parse_mac_and_mask(argv[optind - 1], - cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask)) - xtables_error(PARAMETER_PROBLEM, "Problem with specified " - "source mac"); + args.src_mac = argv[optind - 1]; break; case 3:/* dst-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_D_MAC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_D_MAC, &args.invflags, invert); - - if (xtables_parse_mac_and_mask(argv[optind - 1], - cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask)) - xtables_error(PARAMETER_PROBLEM, "Problem with specified " - "destination mac"); + args.dst_mac = argv[optind - 1]; break; case 'l':/* hardware length */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_H_LENGTH, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_H_LENGTH, &args.invflags, invert); - getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln, - &cs.arp.arp.arhln_mask); - - if (cs.arp.arp.arhln != 6) { - xtables_error(PARAMETER_PROBLEM, - "Only harware address length of" - " 6 is supported currently."); - } - + args.arp_hlen = argv[optind - 1]; break; case 8: /* was never supported, not even in arptables-legacy */ xtables_error(PARAMETER_PROBLEM, "not supported"); case 4:/* opcode */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_OPCODE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_OPCODE, &args.invflags, invert); - if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop, - &cs.arp.arp.arpop_mask, 10)) { - int i; - - for (i = 0; i < NUMOPCODES; i++) - if (!strcasecmp(arp_opcodes[i], optarg)) - break; - if (i == NUMOPCODES) - xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); - cs.arp.arp.arpop = htons(i+1); - } + args.arp_opcode = argv[optind - 1]; break; case 5:/* h-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_H_TYPE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_H_TYPE, &args.invflags, invert); - if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd, - &cs.arp.arp.arhrd_mask, 16)) { - if (strcasecmp(argv[optind-1], "Ethernet")) - xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type"); - cs.arp.arp.arhrd = htons(1); - } + args.arp_htype = argv[optind - 1]; break; case 6:/* proto-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_P_TYPE, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_P_TYPE, &args.invflags, invert); - if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro, - &cs.arp.arp.arpro_mask, 0)) { - if (strcasecmp(argv[optind-1], "ipv4")) - xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type"); - cs.arp.arp.arpro = htons(0x800); - } + args.arp_ptype = argv[optind - 1]; break; case 'j': - set_option(&cs.options, OPT_JUMP, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_JUMP, &args.invflags, invert); command_jump(&cs, optarg); break; case 'i': check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_VIANAMEIN, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_VIANAMEIN, &args.invflags, invert); xtables_parse_interface(argv[optind-1], - cs.arp.arp.iniface, - cs.arp.arp.iniface_mask); + args.iniface, + args.iniface_mask); break; case 'o': check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_VIANAMEOUT, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags, invert); xtables_parse_interface(argv[optind-1], - cs.arp.arp.outiface, - cs.arp.arp.outiface_mask); + args.outiface, + args.outiface_mask); break; case 'v': if (!p.verbose) set_option(&cs.options, OPT_VERBOSE, - &cs.arp.arp.invflags, invert); + &args.invflags, invert); p.verbose++; break; case 'm': /* ignored by arptables-legacy */ break; case 'n': - set_option(&cs.options, OPT_NUMERIC, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_NUMERIC, &args.invflags, invert); break; @@ -715,7 +632,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, exit(0); case '0': - set_option(&cs.options, OPT_LINENUMBERS, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_LINENUMBERS, &args.invflags, invert); break; @@ -725,7 +642,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 'c': - set_option(&cs.options, OPT_COUNTERS, &cs.arp.arp.invflags, + set_option(&cs.options, OPT_COUNTERS, &args.invflags, invert); args.pcnt = optarg; if (xs_has_arg(argc, argv)) @@ -781,25 +698,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); - if (p.command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(cs.options & OPT_DESTINATION)) - args.dhostnetworkmask = "0.0.0.0/0"; - if (!(cs.options & OPT_SOURCE)) - args.shostnetworkmask = "0.0.0.0/0"; - } - - if (args.shostnetworkmask) - xtables_ipparse_multiple(args.shostnetworkmask, &args.s.addr.v4, - &args.s.mask.v4, &args.s.naddrs); - - if (args.dhostnetworkmask) - xtables_ipparse_multiple(args.dhostnetworkmask, &args.d.addr.v4, - &args.d.mask.v4, &args.d.naddrs); - - if ((args.s.naddrs > 1 || args.d.naddrs > 1) && - (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" - " source or destination IP addresses"); + h->ops->post_parse(p.command, &cs, &args); if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1)) xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " -- cgit v1.2.3 From 6cf3976ef7f06b3892a111a3c187c6ca37dbc19e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft-shared: Make nft_check_xt_legacy() family agnostic Of course there is no such thing as *_tables_names for ebtables, so no legacy tables checking for ebtables-nft. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 4253b081..72727270 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -992,6 +992,7 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) { static const char tables6[] = "/proc/net/ip6_tables_names"; static const char tables4[] = "/proc/net/ip_tables_names"; + static const char tablesa[] = "/proc/net/arp_tables_names"; const char *prefix = "ip"; FILE *fp = NULL; char buf[1024]; @@ -1004,6 +1005,10 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) fp = fopen(tables6, "r"); prefix = "ip6"; break; + case NFPROTO_ARP: + fp = fopen(tablesa, "r"); + prefix = "arp"; + break; default: break; } -- cgit v1.2.3 From ab0a785a72a6be0d4a37e3492069a8719418cfbc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: xtables: Derive xtables_globals from family Prepare xtables_main() for use with other families than IPV4 or IPV6 which both use the same xtables_globals object. Therefore introduce a function to map from family value to xtables_globals object pointer. In do_parse(), use xt_params pointer as well instead of direct reference. While being at it, Declare arptables_globals and ebtables_globals in xtables_multi.h which seems to be the proper place for that. Signed-off-by: Phil Sutter --- iptables/xtables-arp-standalone.c | 2 -- iptables/xtables-eb-translate.c | 1 - iptables/xtables-multi.h | 3 +++ iptables/xtables-standalone.c | 23 +++++++++++++++++++---- iptables/xtables.c | 2 +- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c index 04cf7dcc..82db3f38 100644 --- a/iptables/xtables-arp-standalone.c +++ b/iptables/xtables-arp-standalone.c @@ -41,8 +41,6 @@ #include "xtables-multi.h" -extern struct xtables_globals arptables_globals; - int xtables_arp_main(int argc, char *argv[]) { int ret; diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 0539a829..a6c86b65 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -87,7 +87,6 @@ static int parse_rule_number(const char *rule) /* Default command line options. Do not mess around with the already * assigned numbers unless you know what you are doing */ extern struct option ebt_original_options[]; -extern struct xtables_globals ebtables_globals; #define opts ebtables_globals.opts #define prog_name ebtables_globals.program_name #define prog_vers ebtables_globals.program_version diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index 0fedb430..94c24d5a 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -22,6 +22,9 @@ extern int xtables_eb_restore_main(int, char **); extern int xtables_eb_save_main(int, char **); extern int xtables_config_main(int, char **); extern int xtables_monitor_main(int, char **); + +extern struct xtables_globals arptables_globals; +extern struct xtables_globals ebtables_globals; #endif #endif /* _XTABLES_MULTI_H */ diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 54c70c54..19d663b0 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -39,19 +39,34 @@ #include "xtables-multi.h" #include "nft.h" +static struct xtables_globals *xtables_globals_lookup(int family) +{ + switch (family) { + case AF_INET: + case AF_INET6: + return &xtables_globals; + case NFPROTO_ARP: + return &arptables_globals; + case NFPROTO_BRIDGE: + return &ebtables_globals; + default: + xtables_error(OTHER_PROBLEM, "Unknown family value %d", family); + } +} + static int xtables_main(int family, const char *progname, int argc, char *argv[]) { - int ret; char *table = "filter"; struct nft_handle h; + int ret; - xtables_globals.program_name = progname; - ret = xtables_init_all(&xtables_globals, family); + ret = xtables_init_all(xtables_globals_lookup(family), family); if (ret < 0) { fprintf(stderr, "%s: Failed to initialize xtables\n", progname); exit(1); } + xt_params->program_name = progname; #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); @@ -60,7 +75,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) if (nft_init(&h, family) < 0) { fprintf(stderr, "%s: Failed to initialize nft: %s\n", - xtables_globals.program_name, strerror(errno)); + xt_params->program_name, strerror(errno)); exit(EXIT_FAILURE); } diff --git a/iptables/xtables.c b/iptables/xtables.c index 2b3cc930..dc67affc 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -659,7 +659,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], exit_tryhelp(2); default: - if (command_default(cs, &xtables_globals, invert)) + if (command_default(cs, xt_params, invert)) /* cf. ip6tables.c */ continue; break; -- cgit v1.2.3 From 142cf72442760ae8fc377bbfb54a913baf84742e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 14 Nov 2020 15:22:09 +0100 Subject: xtables: arptables accepts empty interface names The empty string passed as interface name is simply ignored by legacy arptables. Make the new common parser print a warning but accept it. Calling xtables_parse_interface() with an empty string is safe. Signed-off-by: Phil Sutter --- iptables/xtables.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/iptables/xtables.c b/iptables/xtables.c index dc67affc..075506f0 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -260,6 +260,19 @@ list_rules(struct nft_handle *h, const char *chain, const char *table, return nft_cmd_rule_list_save(h, chain, table, rulenum, counters); } +static void check_empty_interface(struct nft_handle *h, const char *arg) +{ + const char *msg = "Empty interface is likely to be undesired"; + + if (*arg != '\0') + return; + + if (h->family != NFPROTO_ARP) + xtables_error(PARAMETER_PROBLEM, msg); + + fprintf(stderr, "%s", msg); +} + void do_parse(struct nft_handle *h, int argc, char *argv[], struct nft_xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) @@ -493,10 +506,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'i': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); + check_empty_interface(h, optarg); set_option(&cs->options, OPT_VIANAMEIN, &args->invflags, invert); xtables_parse_interface(optarg, @@ -505,10 +515,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'o': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); + check_empty_interface(h, optarg); set_option(&cs->options, OPT_VIANAMEOUT, &args->invflags, invert); xtables_parse_interface(optarg, -- cgit v1.2.3 From 0af80a91b0a98891d3cbc891a7377281b4080035 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Sep 2021 16:59:49 +0200 Subject: nft: Merge xtables-arp-standalone.c into xtables-standalone.c By declaring the relevant family_ops callbacks for arptables, the code becomes ready to just use do_commandx() instead of a dedicated parser. As a side-effect, this enables a bunch of new features in arptables-nft: * Support '-C' command * Support '-S' command * Support rule indexes just like xtables, e.g. in '-I' or '-R' commands * Reject chain names starting with '!' * Support '-c N,M' counter syntax Since arptables still accepts intrapositioned negations, add code to cover that but print a warning like iptables did 12 years ago prior to removing the functionality. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 2 +- iptables/nft-arp.c | 95 +++++- iptables/xtables-arp-standalone.c | 63 ---- iptables/xtables-arp.c | 638 +------------------------------------- iptables/xtables-restore.c | 2 +- iptables/xtables-standalone.c | 19 +- iptables/xtables.c | 98 +++++- 7 files changed, 218 insertions(+), 699 deletions(-) delete mode 100644 iptables/xtables-arp-standalone.c diff --git a/iptables/Makefile.am b/iptables/Makefile.am index f7895210..0258264c 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -37,7 +37,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \ xtables-standalone.c xtables.c nft.c \ nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \ xtables-monitor.c nft-cache.c \ - xtables-arp-standalone.c xtables-arp.c \ + xtables-arp.c \ nft-bridge.c nft-cmd.c nft-chain.c \ xtables-eb-standalone.c xtables-eb.c \ xtables-eb-translate.c \ diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b37ffbb5..32eb91ad 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -617,7 +617,8 @@ static void nft_arp_post_parse(int command, cs->arp.counters.pcnt = args->pcnt_cnt; cs->arp.counters.bcnt = args->bcnt_cnt; - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { + if (command & (CMD_REPLACE | CMD_INSERT | + CMD_DELETE | CMD_APPEND | CMD_CHECK)) { if (!(cs->options & OPT_DESTINATION)) args->dhostnetworkmask = "0.0.0.0/0"; if (!(cs->options & OPT_SOURCE)) @@ -702,6 +703,94 @@ static void nft_arp_init_cs(struct iptables_command_state *cs) cs->arp.arp.arhrd_mask = 65535; } +static int +nft_arp_add_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + if (append) { + ret = nft_cmd_rule_append(h, chain, table, cs, NULL, + verbose); + } else { + ret = nft_cmd_rule_insert(h, chain, table, cs, + rulenum, verbose); + } + } + } + + return ret; +} + +static int +nft_arp_delete_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_check_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_check(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_replace_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum) +{ + cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr; + cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr; + + return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); +} + struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, @@ -718,4 +807,8 @@ struct nft_family_ops nft_family_ops_arp = { .init_cs = nft_arp_init_cs, .clear_cs = nft_clear_iptables_command_state, .parse_target = nft_ipv46_parse_target, + .add_entry = nft_arp_add_entry, + .delete_entry = nft_arp_delete_entry, + .check_entry = nft_arp_check_entry, + .replace_entry = nft_arp_replace_entry, }; diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c deleted file mode 100644 index 82db3f38..00000000 --- a/iptables/xtables-arp-standalone.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au - * - * Based on the ipchains code by Paul Russell and Michael Neuling - * - * (C) 2000-2002 by the netfilter coreteam : - * Paul 'Rusty' Russell - * Marc Boucher - * James Morris - * Harald Welte - * Jozsef Kadlecsik - * - * arptables -- IP firewall administration for kernels with - * firewall table (aimed for the 2.3 kernels) - * - * See the accompanying manual page arptables(8) for information - * about proper usage of this program. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include "nft.h" -#include - -#include "xtables-multi.h" - -int xtables_arp_main(int argc, char *argv[]) -{ - int ret; - char *table = "filter"; - struct nft_handle h; - - nft_init_arp(&h, "arptables"); - - ret = do_commandarp(&h, argc, argv, &table, false); - if (ret) - ret = nft_commit(&h); - - nft_fini(&h); - xtables_fini(); - - if (!ret) - fprintf(stderr, "arptables: %s\n", nft_strerror(errno)); - - exit(!ret); -} diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index de7c3817..cca19438 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -30,35 +30,23 @@ #include "config.h" #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include "xshared.h" #include "nft.h" #include "nft-arp.h" -#include static struct option original_opts[] = { { "append", 1, 0, 'A' }, { "delete", 1, 0, 'D' }, + { "check", 1, 0, 'C'}, { "insert", 1, 0, 'I' }, { "replace", 1, 0, 'R' }, { "list", 2, 0, 'L' }, + { "list-rules", 2, 0, 'S'}, { "flush", 2, 0, 'F' }, { "zero", 2, 0, 'Z' }, { "new-chain", 1, 0, 'N' }, @@ -101,22 +89,13 @@ static void printhelp(const struct xtables_rule_match *m); struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION, - .optstring = OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */, + .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, .print_help = printhelp, }; -static void -exit_tryhelp(int status) -{ - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - arptables_globals.program_name, - arptables_globals.program_version); - exit(status); -} - static void printhelp(const struct xtables_rule_match *m) { @@ -124,10 +103,12 @@ printhelp(const struct xtables_rule_match *m) int i; printf("%s v%s\n\n" -"Usage: %s -[AD] chain rule-specification [options]\n" -" %s -[RI] chain rulenum rule-specification [options]\n" +"Usage: %s -[ACD] chain rule-specification [options]\n" +" %s -I chain [rulenum] rule-specification [options]\n" +" %s -R chain rulenum rule-specification [options]\n" " %s -D chain rulenum [options]\n" -" %s -[LFZ] [chain] [options]\n" +" %s -[LS] [chain [rulenum]] [options]\n" +" %s -[FZ] [chain] [options]\n" " %s -[NX] chain\n" " %s -E old-chain-name new-chain-name\n" " %s -P chain target [options]\n" @@ -141,11 +122,14 @@ printhelp(const struct xtables_rule_match *m) arptables_globals.program_name, arptables_globals.program_name, arptables_globals.program_name, + arptables_globals.program_name, + arptables_globals.program_name, arptables_globals.program_name); printf( "Commands:\n" "Either long or short options are allowed.\n" " --append -A chain Append to chain\n" +" --check -C chain Check for the existence of a rule\n" " --delete -D chain Delete matching rule from chain\n" " --delete -D chain rulenum\n" " Delete rule rulenum (1 = first) from chain\n" @@ -153,9 +137,13 @@ printhelp(const struct xtables_rule_match *m) " Insert in chain as rulenum (default 1=first)\n" " --replace -R chain rulenum\n" " Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain] List the rules in a chain or all chains\n" +" --list -L [chain [rulenum]]\n" +" List the rules in a chain or all chains\n" +" --list-rules -S [chain [rulenum]]\n" +" Print the rules in a chain or all chains\n" " --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] Zero counters in chain or all chains\n" +" --zero -Z [chain [rulenum]]\n" +" Zero counters in chain or all chains\n" " --new -N chain Create a new user-defined chain\n" " --delete-chain\n" " -X [chain] Delete a user-defined chain\n" @@ -210,134 +198,6 @@ printhelp(const struct xtables_rule_match *m) } } -static int -check_inverse(const char option[], int *invert, int *optidx, int argc) -{ - if (option && strcmp(option, "!") == 0) { - if (*invert) - xtables_error(PARAMETER_PROBLEM, - "Multiple `!' flags not allowed"); - *invert = true; - if (optidx) { - *optidx = *optidx+1; - if (argc && *optidx > argc) - xtables_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } - - return true; - } - return false; -} - -static int -list_entries(struct nft_handle *h, const char *chain, const char *table, - int rulenum, int verbose, int numeric, int expanded, - int linenumbers) -{ - unsigned int format; - - format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else - format |= FMT_VIA; - - if (numeric) - format |= FMT_NUMERIC; - - if (!expanded) - format |= FMT_KILOMEGAGIGA; - - if (linenumbers) - format |= FMT_LINENUMBERS; - - return nft_cmd_rule_list(h, chain, table, rulenum, format); -} - -static int -append_entry(struct nft_handle *h, - const char *chain, - const char *table, - struct iptables_command_state *cs, - int rulenum, - unsigned int nsaddrs, - const struct in_addr saddrs[], - const struct in_addr smasks[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - const struct in_addr dmasks[], - bool verbose, bool append) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - cs->arp.arp.src.s_addr = saddrs[i].s_addr; - cs->arp.arp.smsk.s_addr = smasks[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - cs->arp.arp.tgt.s_addr = daddrs[j].s_addr; - cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr; - if (append) { - ret = nft_cmd_rule_append(h, chain, table, cs, NULL, - verbose); - } else { - ret = nft_cmd_rule_insert(h, chain, table, cs, - rulenum, verbose); - } - } - } - - return ret; -} - -static int -replace_entry(const char *chain, - const char *table, - struct iptables_command_state *cs, - unsigned int rulenum, - const struct in_addr *saddr, - const struct in_addr *smask, - const struct in_addr *daddr, - const struct in_addr *dmask, - bool verbose, struct nft_handle *h) -{ - cs->arp.arp.src.s_addr = saddr->s_addr; - cs->arp.arp.tgt.s_addr = daddr->s_addr; - cs->arp.arp.smsk.s_addr = smask->s_addr; - cs->arp.arp.tmsk.s_addr = dmask->s_addr; - - return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); -} - -static int -delete_entry(const char *chain, - const char *table, - struct iptables_command_state *cs, - unsigned int nsaddrs, - const struct in_addr saddrs[], - const struct in_addr smasks[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - const struct in_addr dmasks[], - bool verbose, struct nft_handle *h) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - cs->arp.arp.src.s_addr = saddrs[i].s_addr; - cs->arp.arp.smsk.s_addr = smasks[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - cs->arp.arp.tgt.s_addr = daddrs[j].s_addr; - cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr; - ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); - } - } - - return ret; -} - int nft_init_arp(struct nft_handle *h, const char *pname) { arptables_globals.program_name = pname; @@ -358,467 +218,3 @@ int nft_init_arp(struct nft_handle *h, const char *pname) return 0; } - -int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, - bool restore) -{ - struct iptables_command_state cs = { - .jumpto = "", - .arp.arp = { - .arhln = 6, - .arhln_mask = 255, - .arhrd = htons(ARPHRD_ETHER), - .arhrd_mask = 65535, - }, - }; - struct nft_xt_cmd_parse p = { - .table = *table, - }; - struct xtables_args args = { - .family = h->family, - }; - int invert = 0; - int ret = 1; - struct xtables_target *t; - - /* re-set optind to 0 in case do_command gets called - * a second time */ - optind = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - - opts = xt_params->orig_opts; - while ((cs.c = getopt_long(argc, argv, xt_params->optstring, - opts, NULL)) != -1) { - switch (cs.c) { - /* - * Command selection - */ - case 'A': - add_command(&p.command, CMD_APPEND, CMD_NONE, - invert); - p.chain = optarg; - break; - - case 'D': - add_command(&p.command, CMD_DELETE, CMD_NONE, - invert); - p.chain = optarg; - if (xs_has_arg(argc, argv)) { - p.rulenum = parse_rulenumber(argv[optind++]); - p.command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&p.command, CMD_REPLACE, CMD_NONE, - invert); - p.chain = optarg; - if (xs_has_arg(argc, argv)) - p.rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&p.command, CMD_INSERT, CMD_NONE, - invert); - p.chain = optarg; - if (xs_has_arg(argc, argv)) - p.rulenum = parse_rulenumber(argv[optind++]); - else p.rulenum = 1; - break; - - case 'L': - add_command(&p.command, CMD_LIST, CMD_ZERO, - invert); - if (optarg) p.chain = optarg; - else if (xs_has_arg(argc, argv)) - p.chain = argv[optind++]; - break; - - case 'F': - add_command(&p.command, CMD_FLUSH, CMD_NONE, - invert); - if (optarg) p.chain = optarg; - else if (xs_has_arg(argc, argv)) - p.chain = argv[optind++]; - break; - - case 'Z': - add_command(&p.command, CMD_ZERO, CMD_LIST, - invert); - if (optarg) p.chain = optarg; - else if (xs_has_arg(argc, argv)) - p.chain = argv[optind++]; - break; - - case 'N': - if (optarg && *optarg == '-') - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `-'\n"); - if (xtables_find_target(optarg, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - add_command(&p.command, CMD_NEW_CHAIN, CMD_NONE, - invert); - p.chain = optarg; - break; - - case 'X': - add_command(&p.command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) p.chain = optarg; - else if (xs_has_arg(argc, argv)) - p.chain = argv[optind++]; - break; - - case 'E': - add_command(&p.command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - p.chain = optarg; - if (xs_has_arg(argc, argv)) - p.newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&p.command, CMD_SET_POLICY, CMD_NONE, - invert); - p.chain = optarg; - if (xs_has_arg(argc, argv)) - p.policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - xt_params->print_help(NULL); - p.command = CMD_NONE; - break; - case 's': - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_SOURCE, &args.invflags, - invert); - args.shostnetworkmask = argv[optind-1]; - break; - - case 'd': - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_DESTINATION, &args.invflags, - invert); - args.dhostnetworkmask = argv[optind-1]; - break; - - case 2:/* src-mac */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_S_MAC, &args.invflags, - invert); - args.src_mac = argv[optind - 1]; - break; - - case 3:/* dst-mac */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_D_MAC, &args.invflags, - invert); - args.dst_mac = argv[optind - 1]; - break; - - case 'l':/* hardware length */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_H_LENGTH, &args.invflags, - invert); - args.arp_hlen = argv[optind - 1]; - break; - - case 8: /* was never supported, not even in arptables-legacy */ - xtables_error(PARAMETER_PROBLEM, "not supported"); - case 4:/* opcode */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_OPCODE, &args.invflags, - invert); - args.arp_opcode = argv[optind - 1]; - break; - - case 5:/* h-type */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_H_TYPE, &args.invflags, - invert); - args.arp_htype = argv[optind - 1]; - break; - - case 6:/* proto-type */ - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_P_TYPE, &args.invflags, - invert); - args.arp_ptype = argv[optind - 1]; - break; - - case 'j': - set_option(&cs.options, OPT_JUMP, &args.invflags, - invert); - command_jump(&cs, optarg); - break; - - case 'i': - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_VIANAMEIN, &args.invflags, - invert); - xtables_parse_interface(argv[optind-1], - args.iniface, - args.iniface_mask); - break; - - case 'o': - check_inverse(optarg, &invert, &optind, argc); - set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags, - invert); - xtables_parse_interface(argv[optind-1], - args.outiface, - args.outiface_mask); - break; - - case 'v': - if (!p.verbose) - set_option(&cs.options, OPT_VERBOSE, - &args.invflags, invert); - p.verbose++; - break; - - case 'm': /* ignored by arptables-legacy */ - break; - case 'n': - set_option(&cs.options, OPT_NUMERIC, &args.invflags, - invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - /* ignore this option. - * arptables-legacy parses it, but libarptc doesn't use it. - * arptables only has a 'filter' table anyway. - */ - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", arptables_globals.program_version); - else - printf("%s v%s (nf_tables)\n", - arptables_globals.program_name, - arptables_globals.program_version); - exit(0); - - case '0': - set_option(&cs.options, OPT_LINENUMBERS, &args.invflags, - invert); - break; - - case 'M': - //modprobe = optarg; - break; - - case 'c': - - set_option(&cs.options, OPT_COUNTERS, &args.invflags, - invert); - args.pcnt = optarg; - if (xs_has_arg(argc, argv)) - args.bcnt = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(args.pcnt, "%llu", &cs.arp.counters.pcnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(args.bcnt, "%llu", &cs.arp.counters.bcnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - - break; - - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - if (cs.target) { - xtables_option_tpcall(cs.c, argv, - invert, cs.target, &cs.arp); - } - break; - } - invert = false; - } - - if (cs.target) - xtables_option_tfcall(cs.target); - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - h->ops->post_parse(p.command, &cs, &args); - - if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - if (p.chain && strlen(p.chain) > ARPT_FUNCTION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %i chars)", - p.chain, ARPT_FUNCTION_MAXNAMELEN); - - if (p.command == CMD_APPEND - || p.command == CMD_DELETE - || p.command == CMD_INSERT - || p.command == CMD_REPLACE) { - if (strcmp(p.chain, "PREROUTING") == 0 - || strcmp(p.chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs.options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - p.chain); - } - - if (strcmp(p.chain, "POSTROUTING") == 0 - || strcmp(p.chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs.options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - p.chain); - } - } - - switch (p.command) { - case CMD_APPEND: - ret = append_entry(h, p.chain, p.table, &cs, 0, - args.s.naddrs, args.s.addr.v4, args.s.mask.v4, - args.d.naddrs, args.d.addr.v4, args.d.mask.v4, - cs.options&OPT_VERBOSE, true); - break; - case CMD_DELETE: - ret = delete_entry(p.chain, p.table, &cs, - args.s.naddrs, args.s.addr.v4, args.s.mask.v4, - args.d.naddrs, args.d.addr.v4, args.d.mask.v4, - cs.options&OPT_VERBOSE, h); - break; - case CMD_DELETE_NUM: - ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose); - break; - case CMD_REPLACE: - ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1, - args.s.addr.v4, args.s.mask.v4, args.d.addr.v4, args.d.mask.v4, - cs.options&OPT_VERBOSE, h); - break; - case CMD_INSERT: - ret = append_entry(h, p.chain, p.table, &cs, p.rulenum - 1, - args.s.naddrs, args.s.addr.v4, args.s.mask.v4, - args.d.naddrs, args.d.addr.v4, args.d.mask.v4, - cs.options&OPT_VERBOSE, false); - break; - case CMD_LIST: - ret = list_entries(h, p.chain, p.table, - p.rulenum, - cs.options&OPT_VERBOSE, - cs.options&OPT_NUMERIC, - /*cs.options&OPT_EXPANDED*/0, - cs.options&OPT_LINENUMBERS); - break; - case CMD_FLUSH: - ret = nft_cmd_rule_flush(h, p.chain, p.table, cs.options & OPT_VERBOSE); - break; - case CMD_ZERO: - ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, - cs.options & OPT_VERBOSE); - break; - case CMD_LIST|CMD_ZERO: - ret = list_entries(h, p.chain, p.table, p.rulenum, - cs.options&OPT_VERBOSE, - cs.options&OPT_NUMERIC, - /*cs.options&OPT_EXPANDED*/0, - cs.options&OPT_LINENUMBERS); - if (ret) - ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, - cs.options & OPT_VERBOSE); - break; - case CMD_NEW_CHAIN: - ret = nft_cmd_chain_user_add(h, p.chain, p.table); - break; - case CMD_DELETE_CHAIN: - ret = nft_cmd_chain_del(h, p.chain, p.table, - cs.options & OPT_VERBOSE); - break; - case CMD_RENAME_CHAIN: - ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname); - break; - case CMD_SET_POLICY: - ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL); - if (ret < 0) - xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n", - p.policy); - break; - case CMD_NONE: - break; - default: - /* We should never reach this... */ - exit_tryhelp(2); - } - - free(args.s.addr.v4); - free(args.s.mask.v4); - free(args.d.addr.v4); - free(args.d.mask.v4); - - nft_clear_iptables_command_state(&cs); - xtables_free_opts(1); - -/* if (p.verbose > 1) - dump_entries(*handle);*/ - - return ret; -} diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 86dcede3..aa8b397f 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -451,7 +451,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) static const struct nft_xt_restore_cb arp_restore_cb = { .commit = nft_commit, .table_flush = nft_cmd_table_flush, - .do_command = do_commandarp, + .do_command = do_commandx, .chain_set = nft_cmd_chain_set, .chain_restore = nft_cmd_chain_restore, }; diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 19d663b0..5482a856 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -68,9 +68,17 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) } xt_params->program_name = progname; #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); - init_extensions4(); - init_extensions6(); + switch (family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + init_extensions(); + init_extensions4(); + init_extensions6(); + break; + case NFPROTO_ARP: + init_extensionsa(); + break; + } #endif if (nft_init(&h, family) < 0) { @@ -107,3 +115,8 @@ int xtables_ip6_main(int argc, char *argv[]) { return xtables_main(NFPROTO_IPV6, "ip6tables", argc, argv); } + +int xtables_arp_main(int argc, char *argv[]) +{ + return xtables_main(NFPROTO_ARP, "arptables", argc, argv); +} diff --git a/iptables/xtables.c b/iptables/xtables.c index 075506f0..5c69af7e 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -36,11 +36,13 @@ #include #include #include +#include #include #include #include #include "xshared.h" #include "nft-shared.h" +#include "nft-arp.h" #include "nft.h" static struct option original_opts[] = { @@ -273,6 +275,34 @@ static void check_empty_interface(struct nft_handle *h, const char *arg) fprintf(stderr, "%s", msg); } +static void check_inverse(struct nft_handle *h, const char option[], + bool *invert, int *optidx, int argc) +{ + switch (h->family) { + case NFPROTO_ARP: + break; + default: + return; + } + + if (!option || strcmp(option, "!")) + return; + + fprintf(stderr, "Using intrapositioned negation (`--option ! this`) " + "is deprecated in favor of extrapositioned (`! --option this`).\n"); + + if (*invert) + xtables_error(PARAMETER_PROBLEM, + "Multiple `!' flags not allowed"); + *invert = true; + if (optidx) { + *optidx = *optidx + 1; + if (argc && *optidx > argc) + xtables_error(PARAMETER_PROBLEM, + "no argument following `!'"); + } +} + void do_parse(struct nft_handle *h, int argc, char *argv[], struct nft_xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) @@ -458,14 +488,16 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], * Option selection */ case 'p': + check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_PROTOCOL, &args->invflags, invert); /* Canonicalize into lower case */ - for (cs->protocol = optarg; *cs->protocol; cs->protocol++) + for (cs->protocol = argv[optind - 1]; + *cs->protocol; cs->protocol++) *cs->protocol = tolower(*cs->protocol); - cs->protocol = optarg; + cs->protocol = argv[optind - 1]; args->proto = xtables_parse_protocol(cs->protocol); if (args->proto == 0 && @@ -474,19 +506,22 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "rule would never match protocol"); /* This needs to happen here to parse extensions */ - h->ops->proto_parse(cs, args); + if (h->ops->proto_parse) + h->ops->proto_parse(cs, args); break; case 's': + check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_SOURCE, &args->invflags, invert); - args->shostnetworkmask = optarg; + args->shostnetworkmask = argv[optind - 1]; break; case 'd': + check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_DESTINATION, &args->invflags, invert); - args->dhostnetworkmask = optarg; + args->dhostnetworkmask = argv[optind - 1]; break; #ifdef IPT_F_GOTO @@ -498,27 +533,72 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; #endif + case 2:/* src-mac */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_S_MAC, &args->invflags, + invert); + args->src_mac = argv[optind - 1]; + break; + + case 3:/* dst-mac */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_D_MAC, &args->invflags, + invert); + args->dst_mac = argv[optind - 1]; + break; + + case 'l':/* hardware length */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_H_LENGTH, &args->invflags, + invert); + args->arp_hlen = argv[optind - 1]; + break; + + case 8: /* was never supported, not even in arptables-legacy */ + xtables_error(PARAMETER_PROBLEM, "not supported"); + case 4:/* opcode */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_OPCODE, &args->invflags, + invert); + args->arp_opcode = argv[optind - 1]; + break; + + case 5:/* h-type */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_H_TYPE, &args->invflags, + invert); + args->arp_htype = argv[optind - 1]; + break; + + case 6:/* proto-type */ + check_inverse(h, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_P_TYPE, &args->invflags, + invert); + args->arp_ptype = argv[optind - 1]; + break; + case 'j': set_option(&cs->options, OPT_JUMP, &args->invflags, invert); - command_jump(cs, optarg); + command_jump(cs, argv[optind - 1]); break; - case 'i': check_empty_interface(h, optarg); + check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEIN, &args->invflags, invert); - xtables_parse_interface(optarg, + xtables_parse_interface(argv[optind - 1], args->iniface, args->iniface_mask); break; case 'o': check_empty_interface(h, optarg); + check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEOUT, &args->invflags, invert); - xtables_parse_interface(optarg, + xtables_parse_interface(argv[optind - 1], args->outiface, args->outiface_mask); break; -- cgit v1.2.3 From b8d5271de4f7cc6ffeeca589ea4706e316599015 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 6 Nov 2021 21:38:14 +0100 Subject: Unbreak xtables-translate Fixed commit broke xtables-translate which still relied upon do_parse() to properly initialize the passed iptables_command_state reference. To allow for callers to preset fields, this doesn't happen anymore so do_command_xlate() has to initialize itself. Otherwise garbage from stack is read leading to segfaults and program aborts. Although init_cs callback is used by arptables only and arptables-translate has not been implemented, do call it if set just to avoid future issues. Fixes: cfdda18044d81 ("nft-shared: Introduce init_cs family ops callback") Signed-off-by: Phil Sutter Tested-by: Pablo Neira Ayuso --- iptables/xtables-translate.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 086b85d2..e2948c50 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -253,11 +253,18 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], .restore = restore, .xlate = true, }; - struct iptables_command_state cs; + struct iptables_command_state cs = { + .jumpto = "", + .argv = argv, + }; + struct xtables_args args = { .family = h->family, }; + if (h->ops->init_cs) + h->ops->init_cs(&cs); + do_parse(h, argc, argv, &p, &cs, &args); cs.restore = restore; -- cgit v1.2.3 From afa525ee81aa799284c35575c945785fa8b82b13 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 6 Nov 2021 21:10:45 +0100 Subject: xlate-test: Print full path if testing all files Lines won't become too long and it's more clear to users where test input comes from this way. Signed-off-by: Phil Sutter Tested-by: Pablo Neira Ayuso --- xlate-test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 4a56e798..d78e8648 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -80,15 +80,15 @@ def run_test(name, payload): def load_test_files(): test_files = total_tests = total_passed = total_error = total_failed = 0 - for test in sorted(os.listdir("extensions")): - if test.endswith(".txlate"): - with open("extensions/" + test, "r") as payload: - tests, passed, failed, errors = run_test(test, payload) - test_files += 1 - total_tests += tests - total_passed += passed - total_failed += failed - total_error += errors + tests = sorted(os.listdir("extensions")) + for test in ['extensions/' + f for f in tests if f.endswith(".txlate")]: + with open(test, "r") as payload: + tests, passed, failed, errors = run_test(test, payload) + test_files += 1 + total_tests += tests + total_passed += passed + total_failed += failed + total_error += errors return (test_files, total_tests, total_passed, total_failed, total_error) -- cgit v1.2.3 From 1eab8e83aec0e6965f11f8cad460add1caeae629 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 8 Nov 2021 17:03:21 +0100 Subject: extensions: hashlimit: Fix tests with HZ=1000 In an attempt to fix for failing hashlimit tests with HZ=100, the expected failures were changed so they are expected to pass and the parameters changed to seemingly fix them. Yet while the new parameters worked on HZ=100 systems, with higher tick rates they didn't so the observed problem moved from the test failing on HZ=100 to failing on HZ=1000 instead. Kernel's error message "try lower: 864000000/5" turned out to be a red herring: The burst value does not act as a dividor but a multiplier instead, so in order to lower the overflow-checked value, a lower burst value must be chosen. Inded, using a burst value of 1 makes the kernel accept the rule in both HZ=100 and HZ=1000 configurations. Fixes: bef9dc575625a ("extensions: hashlimit: Fix tests with HZ=100") Signed-off-by: Phil Sutter --- extensions/libxt_hashlimit.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t index 83699337..206d9293 100644 --- a/extensions/libxt_hashlimit.t +++ b/extensions/libxt_hashlimit.t @@ -3,12 +3,12 @@ -m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK --m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK --m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK -- cgit v1.2.3 From 1189d830ea4fd269da87761d400ebabca02e1ef3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Apr 2019 13:21:19 +0200 Subject: xshared: Merge and share parse_chain() Have a common routine to perform chain name checks, combining all variants' requirements. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 26 -------------------------- iptables/iptables.c | 25 ------------------------- iptables/xshared.c | 24 ++++++++++++++++++++++++ iptables/xshared.h | 1 + iptables/xtables.c | 9 +-------- 5 files changed, 26 insertions(+), 59 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index e967c040..ec0ae759 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -233,32 +233,6 @@ static int is_exthdr(uint16_t proto) proto == IPPROTO_DSTOPTS); } -static void -parse_chain(const char *chainname) -{ - const char *ptr; - - if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %u chars)", - chainname, XT_EXTENSION_MAXNAMELEN); - - if (*chainname == '-' || *chainname == '!') - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `%c'\n", *chainname); - - if (xtables_find_target(chainname, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - - for (ptr = chainname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s'", chainname); -} - static void print_header(unsigned int format, const char *chain, struct xtc_handle *handle) { diff --git a/iptables/iptables.c b/iptables/iptables.c index b925f089..246526a5 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -223,31 +223,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static void -parse_chain(const char *chainname) -{ - const char *ptr; - - if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %u chars)", - chainname, XT_EXTENSION_MAXNAMELEN); - - if (*chainname == '-' || *chainname == '!') - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `%c'\n", *chainname); - - if (xtables_find_target(chainname, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - - for (ptr = chainname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s'", chainname); -} static void print_header(unsigned int format, const char *chain, struct xtc_handle *handle) diff --git a/iptables/xshared.c b/iptables/xshared.c index 2d3ef679..bd545d6b 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -892,3 +892,27 @@ set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, *invflg |= inverse_for_options[i]; } } + +void parse_chain(const char *chainname) +{ + const char *ptr; + + if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, + "chain name `%s' too long (must be under %u chars)", + chainname, XT_EXTENSION_MAXNAMELEN); + + if (*chainname == '-' || *chainname == '!') + xtables_error(PARAMETER_PROBLEM, + "chain name not allowed to start with `%c'\n", + *chainname); + + if (xtables_find_target(chainname, XTF_TRY_LOAD)) + xtables_error(PARAMETER_PROBLEM, + "chain name may not clash with target name\n"); + + for (ptr = chainname; *ptr; ptr++) + if (isspace(*ptr)) + xtables_error(PARAMETER_PROBLEM, + "Invalid chain name `%s'", chainname); +} diff --git a/iptables/xshared.h b/iptables/xshared.h index b59116ac..6d6acbca 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -235,6 +235,7 @@ char cmd2char(int option); void add_command(unsigned int *cmd, const int newcmd, const int othercmds, int invert); int parse_rulenumber(const char *rule); +void parse_chain(const char *chainname); void generic_opt_check(int command, int options); char opt2char(int option); diff --git a/iptables/xtables.c b/iptables/xtables.c index 5c69af7e..32b93d2b 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -424,14 +424,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'N': - if (optarg && (*optarg == '-' || *optarg == '!')) - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `%c'\n", *optarg); - if (xtables_find_target(optarg, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); + parse_chain(optarg); add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE, invert); p->chain = optarg; -- cgit v1.2.3 From b5881e7f22d42a8b00acbdbab296b71572ddb903 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Nov 2021 17:45:48 +0100 Subject: nft: Change whitespace printing in save_rule callback This aligns whitespace printing with legacy iptables' print_rule4() in order to prepare for further code-sharing. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 1 + iptables/nft-bridge.c | 10 ++++++++-- iptables/nft-ipv4.c | 6 +++--- iptables/nft-ipv6.c | 8 ++++---- iptables/nft-shared.c | 26 ++++++++++++-------------- iptables/nft.c | 4 ++-- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 32eb91ad..b7536e61 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -479,6 +479,7 @@ nft_arp_save_rule(const void *data, unsigned int format) format |= FMT_NUMERIC; + printf(" "); nft_arp_print_rule_details(cs, format); if (cs->target && cs->target->save) cs->target->save(&cs->fw, cs->target->t); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 11f3df35..cc2a48db 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -601,7 +601,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("%s ", ent->e_name); } -static void nft_bridge_save_rule(const void *data, unsigned int format) +static void __nft_bridge_save_rule(const void *data, unsigned int format) { const struct iptables_command_state *cs = data; @@ -652,6 +652,12 @@ static void nft_bridge_save_rule(const void *data, unsigned int format) fputc('\n', stdout); } +static void nft_bridge_save_rule(const void *data, unsigned int format) +{ + printf(" "); + __nft_bridge_save_rule(data, format); +} + static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format) { @@ -661,7 +667,7 @@ static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, printf("%d ", num); nft_rule_to_ebtables_command_state(h, r, &cs); - nft_bridge_save_rule(&cs, format); + __nft_bridge_save_rule(&cs, format); ebt_cs_clean(&cs); } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index febd7673..287112d0 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -303,7 +303,7 @@ static void save_ipv4_addr(char letter, const struct in_addr *addr, if (!mask && !invert && !addr->s_addr) return; - printf("%s-%c %s/%s ", invert ? "! " : "", letter, + printf("%s -%c %s/%s", invert ? " !" : "", letter, inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)), mask_to_str(mask)); } @@ -323,8 +323,8 @@ static void nft_ipv4_save_rule(const void *data, unsigned int format) if (cs->fw.ip.flags & IPT_F_FRAG) { if (cs->fw.ip.invflags & IPT_INV_FRAG) - printf("! "); - printf("-f "); + printf(" !"); + printf(" -f"); } save_matches_and_target(cs, cs->fw.ip.flags & IPT_F_GOTO, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index f0e64bbd..845937b1 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -234,14 +234,14 @@ static void save_ipv6_addr(char letter, const struct in6_addr *addr, if (!invert && l == 0) return; - printf("%s-%c %s", - invert ? "! " : "", letter, + printf("%s -%c %s", + invert ? " !" : "", letter, inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str))); if (l == -1) - printf("/%s ", inet_ntop(AF_INET6, mask, addr_str, sizeof(addr_str))); + printf("/%s", inet_ntop(AF_INET6, mask, addr_str, sizeof(addr_str))); else - printf("/%d ", l); + printf("/%d", l); } static void nft_ipv6_save_rule(const void *data, unsigned int format) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 72727270..082cc0e2 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -793,7 +793,7 @@ print_iface(char letter, const char *iface, const unsigned char *mask, int inv) if (mask[0] == 0) return; - printf("%s-%c ", inv ? "! " : "", letter); + printf("%s -%c ", inv ? " !" : "", letter); for (i = 0; i < IFNAMSIZ; i++) { if (mask[i] != 0) { @@ -805,8 +805,6 @@ print_iface(char letter, const char *iface, const unsigned char *mask, int inv) break; } } - - printf(" "); } void save_rule_details(const struct iptables_command_state *cs, @@ -829,12 +827,12 @@ void save_rule_details(const struct iptables_command_state *cs, const char *pname = proto_to_name(proto, 0); if (invflags & XT_INV_PROTO) - printf("! "); + printf(" !"); if (pname) - printf("-p %s ", pname); + printf(" -p %s", pname); else - printf("-p %u ", proto); + printf(" -p %u", proto); } } @@ -856,33 +854,33 @@ void save_matches_and_target(const struct iptables_command_state *cs, for (matchp = cs->matches; matchp; matchp = matchp->next) { if (matchp->match->alias) { - printf("-m %s", + printf(" -m %s", matchp->match->alias(matchp->match->m)); } else - printf("-m %s", matchp->match->name); + printf(" -m %s", matchp->match->name); if (matchp->match->save != NULL) { /* cs->fw union makes the trick */ matchp->match->save(fw, matchp->match->m); } - printf(" "); } if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS) - printf("-c %llu %llu ", + printf(" -c %llu %llu", (unsigned long long)cs->counters.pcnt, (unsigned long long)cs->counters.bcnt); if (cs->target != NULL) { if (cs->target->alias) { - printf("-j %s", cs->target->alias(cs->target->t)); + printf(" -j %s", cs->target->alias(cs->target->t)); } else - printf("-j %s", cs->jumpto); + printf(" -j %s", cs->jumpto); - if (cs->target->save != NULL) + if (cs->target->save != NULL) { cs->target->save(fw, cs->target->t); + } } else if (strlen(cs->jumpto) > 0) { - printf("-%c %s", goto_flag ? 'g' : 'j', cs->jumpto); + printf(" -%c %s", goto_flag ? 'g' : 'j', cs->jumpto); } printf("\n"); diff --git a/iptables/nft.c b/iptables/nft.c index 1d3f3a3d..282d417f 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1513,10 +1513,10 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, /* print chain name */ switch(type) { case NFT_RULE_APPEND: - printf("-A %s ", chain); + printf("-A %s", chain); break; case NFT_RULE_DEL: - printf("-D %s ", chain); + printf("-D %s", chain); break; } -- cgit v1.2.3 From 766e4872e10bccc12fa37dcf5380d3c99fcf1d75 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Nov 2021 18:02:13 +0100 Subject: xshared: Share print_iface() function Merge the three identical copies into one and name it 'save_iface' (as the printed syntax is for "save"-format). Leave arptables alone for now, its rather complicated whitespace printing doesn't allow for use of the shared function. Also keep ebtables' custom implementation, it is used for the --logical-in/--logical-out long-options, too. Apart from that, ebtables-nft does not use a mask, at all. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 30 ++---------------------------- iptables/iptables.c | 30 ++---------------------------- iptables/nft-shared.c | 26 ++------------------------ iptables/xshared.c | 25 +++++++++++++++++++++++++ iptables/xshared.h | 2 ++ 5 files changed, 33 insertions(+), 80 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index ec0ae759..1c9b0761 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -707,32 +707,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -/* This assumes that mask is contiguous, and byte-bounded. */ -static void -print_iface(char letter, const char *iface, const unsigned char *mask, - int invert) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s -%c ", invert ? " !" : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - /* we can access iface[i-1] here, because - * a few lines above we make sure that mask[0] != 0 */ - if (iface[i-1] != '\0') - printf("+"); - break; - } - } -} - static void print_proto(uint16_t proto, int invert) { if (proto) { @@ -821,10 +795,10 @@ void print_rule6(const struct ip6t_entry *e, print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), e->ipv6.invflags & IP6T_INV_DSTIP); - print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, + save_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, e->ipv6.invflags & IP6T_INV_VIA_IN); - print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, + save_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, e->ipv6.invflags & IP6T_INV_VIA_OUT); print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO); diff --git a/iptables/iptables.c b/iptables/iptables.c index 246526a5..7802bd6d 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -720,32 +720,6 @@ static void print_proto(uint16_t proto, int invert) #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) -/* This assumes that mask is contiguous, and byte-bounded. */ -static void -print_iface(char letter, const char *iface, const unsigned char *mask, - int invert) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s -%c ", invert ? " !" : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - /* we can access iface[i-1] here, because - * a few lines above we make sure that mask[0] != 0 */ - if (iface[i-1] != '\0') - printf("+"); - break; - } - } -} - static int print_match_save(const struct xt_entry_match *e, const struct ipt_ip *ip) { @@ -830,10 +804,10 @@ void print_rule4(const struct ipt_entry *e, print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, e->ip.invflags & IPT_INV_DSTIP); - print_iface('i', e->ip.iniface, e->ip.iniface_mask, + save_iface('i', e->ip.iniface, e->ip.iniface_mask, e->ip.invflags & IPT_INV_VIA_IN); - print_iface('o', e->ip.outiface, e->ip.outiface_mask, + save_iface('o', e->ip.outiface, e->ip.outiface_mask, e->ip.invflags & IPT_INV_VIA_OUT); print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 082cc0e2..b86cc086 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -785,28 +785,6 @@ void print_rule_details(const struct iptables_command_state *cs, } } -static void -print_iface(char letter, const char *iface, const unsigned char *mask, int inv) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s -%c ", inv ? " !" : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - if (iface[i-1] != '\0') - printf("+"); - break; - } - } -} - void save_rule_details(const struct iptables_command_state *cs, uint8_t invflags, uint16_t proto, const char *iniface, @@ -815,11 +793,11 @@ void save_rule_details(const struct iptables_command_state *cs, unsigned const char *outiface_mask) { if (iniface != NULL) { - print_iface('i', iniface, iniface_mask, + save_iface('i', iniface, iniface_mask, invflags & IPT_INV_VIA_IN); } if (outiface != NULL) { - print_iface('o', outiface, outiface_mask, + save_iface('o', outiface, outiface_mask, invflags & IPT_INV_VIA_OUT); } diff --git a/iptables/xshared.c b/iptables/xshared.c index bd545d6b..db03aaaa 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -637,6 +637,31 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, printf(FMT("%-6s ", "out %s "), iface); } +/* This assumes that mask is contiguous, and byte-bounded. */ +void save_iface(char letter, const char *iface, + const unsigned char *mask, int invert) +{ + unsigned int i; + + if (mask[0] == 0) + return; + + printf("%s -%c ", invert ? " !" : "", letter); + + for (i = 0; i < IFNAMSIZ; i++) { + if (mask[i] != 0) { + if (iface[i] != '\0') + printf("%c", iface[i]); + } else { + /* we can access iface[i-1] here, because + * a few lines above we make sure that mask[0] != 0 */ + if (iface[i-1] != '\0') + printf("+"); + break; + } + } +} + void command_match(struct iptables_command_state *cs, bool invert) { struct option *opts = xt_params->opts; diff --git a/iptables/xshared.h b/iptables/xshared.h index 6d6acbca..3281ce58 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -226,6 +226,8 @@ void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format); void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, unsigned int format); +void save_iface(char letter, const char *iface, + const unsigned char *mask, int invert); void command_match(struct iptables_command_state *cs, bool invert); const char *xt_parse_target(const char *targetname); -- cgit v1.2.3 From 22f2e1fca127b014dccf1006544e3179c9dc9764 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Nov 2021 18:27:53 +0100 Subject: xshared: Share save_rule_details() with legacy The function combines printing of input and output interfaces and protocol parameter, all being IP family independent. Extend the function to print fragment option ('-f'), too if requested. While being at it, drop unused iptables_command_state parameter and reorder the remaining ones a bit. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 23 +++-------------------- iptables/iptables.c | 28 ++++------------------------ iptables/nft-ipv4.c | 13 ++++--------- iptables/nft-ipv6.c | 6 +++--- iptables/nft-shared.c | 29 ----------------------------- iptables/nft-shared.h | 6 ------ iptables/xshared.c | 32 ++++++++++++++++++++++++++++++++ iptables/xshared.h | 4 ++++ 8 files changed, 50 insertions(+), 91 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 1c9b0761..eacbf704 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -707,19 +707,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -static void print_proto(uint16_t proto, int invert) -{ - if (proto) { - const char *pname = proto_to_name(proto, 0); - const char *invertstr = invert ? " !" : ""; - - if (pname) - printf("%s -p %s", invertstr, pname); - else - printf("%s -p %u", invertstr, proto); - } -} - static int print_match_save(const struct xt_entry_match *e, const struct ip6t_ip6 *ip) { @@ -795,13 +782,9 @@ void print_rule6(const struct ip6t_entry *e, print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), e->ipv6.invflags & IP6T_INV_DSTIP); - save_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, - e->ipv6.invflags & IP6T_INV_VIA_IN); - - save_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, - e->ipv6.invflags & IP6T_INV_VIA_OUT); - - print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO); + save_rule_details(e->ipv6.iniface, e->ipv6.iniface_mask, + e->ipv6.outiface, e->ipv6.outiface_mask, + e->ipv6.proto, 0, e->ipv6.invflags); #if 0 /* not definied in ipv6 diff --git a/iptables/iptables.c b/iptables/iptables.c index 7802bd6d..85fb7bdc 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -699,19 +699,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -static void print_proto(uint16_t proto, int invert) -{ - if (proto) { - const char *pname = proto_to_name(proto, 0); - const char *invertstr = invert ? " !" : ""; - - if (pname) - printf("%s -p %s", invertstr, pname); - else - printf("%s -p %u", invertstr, proto); - } -} - #define IP_PARTS_NATIVE(n) \ (unsigned int)((n)>>24)&0xFF, \ (unsigned int)((n)>>16)&0xFF, \ @@ -804,17 +791,10 @@ void print_rule4(const struct ipt_entry *e, print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, e->ip.invflags & IPT_INV_DSTIP); - save_iface('i', e->ip.iniface, e->ip.iniface_mask, - e->ip.invflags & IPT_INV_VIA_IN); - - save_iface('o', e->ip.outiface, e->ip.outiface_mask, - e->ip.invflags & IPT_INV_VIA_OUT); - - print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO); - - if (e->ip.flags & IPT_F_FRAG) - printf("%s -f", - e->ip.invflags & IPT_INV_FRAG ? " !" : ""); + save_rule_details(e->ip.iniface, e->ip.iniface_mask, + e->ip.outiface, e->ip.outiface_mask, + e->ip.proto, e->ip.flags & IPT_F_FRAG, + e->ip.invflags); /* Print matchinfo part */ if (e->target_offset) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 287112d0..39d6e612 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -317,15 +317,10 @@ static void nft_ipv4_save_rule(const void *data, unsigned int format) save_ipv4_addr('d', &cs->fw.ip.dst, cs->fw.ip.dmsk.s_addr, cs->fw.ip.invflags & IPT_INV_DSTIP); - save_rule_details(cs, cs->fw.ip.invflags, cs->fw.ip.proto, - cs->fw.ip.iniface, cs->fw.ip.iniface_mask, - cs->fw.ip.outiface, cs->fw.ip.outiface_mask); - - if (cs->fw.ip.flags & IPT_F_FRAG) { - if (cs->fw.ip.invflags & IPT_INV_FRAG) - printf(" !"); - printf(" -f"); - } + save_rule_details(cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + cs->fw.ip.outiface, cs->fw.ip.outiface_mask, + cs->fw.ip.proto, cs->fw.ip.flags & IPT_F_FRAG, + cs->fw.ip.invflags); save_matches_and_target(cs, cs->fw.ip.flags & IPT_F_GOTO, &cs->fw, format); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 845937b1..0c73cedd 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -253,9 +253,9 @@ static void nft_ipv6_save_rule(const void *data, unsigned int format) save_ipv6_addr('d', &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, cs->fw6.ipv6.invflags & IP6T_INV_DSTIP); - save_rule_details(cs, cs->fw6.ipv6.invflags, cs->fw6.ipv6.proto, - cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, - cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask); + save_rule_details(cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, + cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask, + cs->fw6.ipv6.proto, 0, cs->fw6.ipv6.invflags); save_matches_and_target(cs, cs->fw6.ipv6.flags & IP6T_F_GOTO, &cs->fw6, format); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index b86cc086..168c2246 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -785,35 +785,6 @@ void print_rule_details(const struct iptables_command_state *cs, } } -void save_rule_details(const struct iptables_command_state *cs, - uint8_t invflags, uint16_t proto, - const char *iniface, - unsigned const char *iniface_mask, - const char *outiface, - unsigned const char *outiface_mask) -{ - if (iniface != NULL) { - save_iface('i', iniface, iniface_mask, - invflags & IPT_INV_VIA_IN); - } - if (outiface != NULL) { - save_iface('o', outiface, outiface_mask, - invflags & IPT_INV_VIA_OUT); - } - - if (proto > 0) { - const char *pname = proto_to_name(proto, 0); - - if (invflags & XT_INV_PROTO) - printf(" !"); - - if (pname) - printf(" -p %s", pname); - else - printf(" -p %u", proto); - } -} - void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) { const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 339c46e7..cac5757f 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -173,12 +173,6 @@ void print_rule_details(const struct iptables_command_state *cs, unsigned int num, unsigned int format); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); -void save_rule_details(const struct iptables_command_state *cs, - uint8_t invflags, uint16_t proto, - const char *iniface, - unsigned const char *iniface_mask, - const char *outiface, - unsigned const char *outiface_mask); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); void save_matches_and_target(const struct iptables_command_state *cs, bool goto_flag, const void *fw, diff --git a/iptables/xshared.c b/iptables/xshared.c index db03aaaa..db701ead 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -941,3 +941,35 @@ void parse_chain(const char *chainname) xtables_error(PARAMETER_PROBLEM, "Invalid chain name `%s'", chainname); } + +void save_rule_details(const char *iniface, unsigned const char *iniface_mask, + const char *outiface, unsigned const char *outiface_mask, + uint16_t proto, int frag, uint8_t invflags) +{ + if (iniface != NULL) { + save_iface('i', iniface, iniface_mask, + invflags & IPT_INV_VIA_IN); + } + if (outiface != NULL) { + save_iface('o', outiface, outiface_mask, + invflags & IPT_INV_VIA_OUT); + } + + if (proto > 0) { + const char *pname = proto_to_name(proto, 0); + + if (invflags & XT_INV_PROTO) + printf(" !"); + + if (pname) + printf(" -p %s", pname); + else + printf(" -p %u", proto); + } + + if (frag) { + if (invflags & IPT_INV_FRAG) + printf(" !"); + printf(" -f"); + } +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 3281ce58..484ade12 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -242,4 +242,8 @@ void parse_chain(const char *chainname); void generic_opt_check(int command, int options); char opt2char(int option); +void save_rule_details(const char *iniface, unsigned const char *iniface_mask, + const char *outiface, unsigned const char *outiface_mask, + uint16_t proto, int frag, uint8_t invflags); + #endif /* IPTABLES_XSHARED_H */ -- cgit v1.2.3 From e5fb9f8efaa0643a566d079c8201082822a0dc81 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Nov 2021 18:50:21 +0100 Subject: xshared: Share save_ipv{4,6}_addr() with legacy While being at it, make save_ipv4_addr() accept an in_addr* as mask - mask_to_str() needs it anyway. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 29 ++++---------------------- iptables/iptables.c | 36 +++------------------------------ iptables/nft-ipv4.c | 43 ++------------------------------------- iptables/nft-ipv6.c | 20 ------------------ iptables/xshared.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ iptables/xshared.h | 4 ++++ 6 files changed, 70 insertions(+), 119 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index eacbf704..5c118626 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -738,27 +738,6 @@ static int print_match_save(const struct xt_entry_match *e, return 0; } -/* Print a given ip including mask if necessary. */ -static void print_ip(const char *prefix, const struct in6_addr *ip, - const struct in6_addr *mask, int invert) -{ - char buf[51]; - int l = xtables_ip6mask_to_cidr(mask); - - if (l == 0 && !invert) - return; - - printf("%s %s %s", - invert ? " !" : "", - prefix, - inet_ntop(AF_INET6, ip, buf, sizeof buf)); - - if (l == -1) - printf("/%s", inet_ntop(AF_INET6, mask, buf, sizeof buf)); - else - printf("/%d", l); -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ @@ -776,11 +755,11 @@ void print_rule6(const struct ip6t_entry *e, printf("-A %s", chain); /* Print IP part. */ - print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk), - e->ipv6.invflags & IP6T_INV_SRCIP); + save_ipv6_addr('s', &e->ipv6.src, &e->ipv6.smsk, + e->ipv6.invflags & IP6T_INV_SRCIP); - print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), - e->ipv6.invflags & IP6T_INV_DSTIP); + save_ipv6_addr('d', &e->ipv6.dst, &e->ipv6.dmsk, + e->ipv6.invflags & IP6T_INV_DSTIP); save_rule_details(e->ipv6.iniface, e->ipv6.iniface_mask, e->ipv6.outiface, e->ipv6.outiface_mask, diff --git a/iptables/iptables.c b/iptables/iptables.c index 85fb7bdc..0d8beb04 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -738,36 +738,6 @@ static int print_match_save(const struct xt_entry_match *e, return 0; } -/* Print a given ip including mask if necessary. */ -static void print_ip(const char *prefix, uint32_t ip, - uint32_t mask, int invert) -{ - uint32_t bits, hmask = ntohl(mask); - int i; - - if (!mask && !ip && !invert) - return; - - printf("%s %s %u.%u.%u.%u", - invert ? " !" : "", - prefix, - IP_PARTS(ip)); - - if (mask == 0xFFFFFFFFU) { - printf("/32"); - return; - } - - i = 32; - bits = 0xFFFFFFFEU; - while (--i >= 0 && hmask != bits) - bits <<= 1; - if (i >= 0) - printf("/%u", i); - else - printf("/%u.%u.%u.%u", IP_PARTS(mask)); -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ @@ -785,10 +755,10 @@ void print_rule4(const struct ipt_entry *e, printf("-A %s", chain); /* Print IP part. */ - print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, - e->ip.invflags & IPT_INV_SRCIP); + save_ipv4_addr('s', &e->ip.src, &e->ip.smsk, + e->ip.invflags & IPT_INV_SRCIP); - print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, + save_ipv4_addr('d', &e->ip.dst, &e->ip.dmsk, e->ip.invflags & IPT_INV_DSTIP); save_rule_details(e->ip.iniface, e->ip.iniface_mask, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 39d6e612..dcc009cf 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -134,32 +134,6 @@ static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) ctx->flags &= ~NFT_XT_CTX_BITWISE; } -static const char *mask_to_str(uint32_t mask) -{ - static char mask_str[INET_ADDRSTRLEN]; - uint32_t bits, hmask = ntohl(mask); - struct in_addr mask_addr = { - .s_addr = mask, - }; - int i; - - if (mask == 0xFFFFFFFFU) { - sprintf(mask_str, "32"); - return mask_str; - } - - i = 32; - bits = 0xFFFFFFFEU; - while (--i >= 0 && hmask != bits) - bits <<= 1; - if (i >= 0) - sprintf(mask_str, "%u", i); - else - inet_ntop(AF_INET, &mask_addr, mask_str, sizeof(mask_str)); - - return mask_str; -} - static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, void *data) { @@ -295,26 +269,13 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_clear_iptables_command_state(&cs); } -static void save_ipv4_addr(char letter, const struct in_addr *addr, - uint32_t mask, int invert) -{ - char addrbuf[INET_ADDRSTRLEN]; - - if (!mask && !invert && !addr->s_addr) - return; - - printf("%s -%c %s/%s", invert ? " !" : "", letter, - inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)), - mask_to_str(mask)); -} - static void nft_ipv4_save_rule(const void *data, unsigned int format) { const struct iptables_command_state *cs = data; - save_ipv4_addr('s', &cs->fw.ip.src, cs->fw.ip.smsk.s_addr, + save_ipv4_addr('s', &cs->fw.ip.src, &cs->fw.ip.smsk, cs->fw.ip.invflags & IPT_INV_SRCIP); - save_ipv4_addr('d', &cs->fw.ip.dst, cs->fw.ip.dmsk.s_addr, + save_ipv4_addr('d', &cs->fw.ip.dst, &cs->fw.ip.dmsk, cs->fw.ip.invflags & IPT_INV_DSTIP); save_rule_details(cs->fw.ip.iniface, cs->fw.ip.iniface_mask, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 0c73cedd..0b35e045 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -224,26 +224,6 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_clear_iptables_command_state(&cs); } -static void save_ipv6_addr(char letter, const struct in6_addr *addr, - const struct in6_addr *mask, - int invert) -{ - char addr_str[INET6_ADDRSTRLEN]; - int l = xtables_ip6mask_to_cidr(mask); - - if (!invert && l == 0) - return; - - printf("%s -%c %s", - invert ? " !" : "", letter, - inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str))); - - if (l == -1) - printf("/%s", inet_ntop(AF_INET6, mask, addr_str, sizeof(addr_str))); - else - printf("/%d", l); -} - static void nft_ipv6_save_rule(const void *data, unsigned int format) { const struct iptables_command_state *cs = data; diff --git a/iptables/xshared.c b/iptables/xshared.c index db701ead..3e06960f 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -578,6 +579,42 @@ void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format) ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format)); } +static const char *mask_to_str(const struct in_addr *mask) +{ + uint32_t bits, hmask = ntohl(mask->s_addr); + static char mask_str[INET_ADDRSTRLEN]; + int i; + + if (mask->s_addr == 0xFFFFFFFFU) { + sprintf(mask_str, "32"); + return mask_str; + } + + i = 32; + bits = 0xFFFFFFFEU; + while (--i >= 0 && hmask != bits) + bits <<= 1; + if (i >= 0) + sprintf(mask_str, "%u", i); + else + inet_ntop(AF_INET, mask, mask_str, sizeof(mask_str)); + + return mask_str; +} + +void save_ipv4_addr(char letter, const struct in_addr *addr, + const struct in_addr *mask, int invert) +{ + char addrbuf[INET_ADDRSTRLEN]; + + if (!mask->s_addr && !invert && !addr->s_addr) + return; + + printf("%s -%c %s/%s", invert ? " !" : "", letter, + inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)), + mask_to_str(mask)); +} + static const char *ipv6_addr_to_string(const struct in6_addr *addr, const struct in6_addr *mask, unsigned int format) @@ -612,6 +649,26 @@ void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format) &fw6->ipv6.dmsk, format)); } +void save_ipv6_addr(char letter, const struct in6_addr *addr, + const struct in6_addr *mask, int invert) +{ + int l = xtables_ip6mask_to_cidr(mask); + char addr_str[INET6_ADDRSTRLEN]; + + if (!invert && l == 0) + return; + + printf("%s -%c %s", + invert ? " !" : "", letter, + inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str))); + + if (l == -1) + printf("/%s", inet_ntop(AF_INET6, mask, + addr_str, sizeof(addr_str))); + else + printf("/%d", l); +} + /* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT * so this function serves for both iptables and ip6tables */ diff --git a/iptables/xshared.h b/iptables/xshared.h index 484ade12..46ad5a29 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -222,7 +222,11 @@ const char *ipv4_addr_to_string(const struct in_addr *addr, const struct in_addr *mask, unsigned int format); void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format); +void save_ipv4_addr(char letter, const struct in_addr *addr, + const struct in_addr *mask, int invert); void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format); +void save_ipv6_addr(char letter, const struct in6_addr *addr, + const struct in6_addr *mask, int invert); void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, unsigned int format); -- cgit v1.2.3 From 1d73cec02c8d9a0f5bfbd2983c36cc1228b78f45 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 Nov 2021 22:02:45 +0100 Subject: xshared: Share print_rule_details() with legacy Have to pass pointer to counters directly since different fields are being used for some reason. Since proto_to_name() is not used outside of xshared.c anymore, make it static. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 21 ++------------------- iptables/iptables.c | 21 ++------------------- iptables/nft-ipv4.c | 4 ++-- iptables/nft-ipv6.c | 5 ++--- iptables/nft-shared.c | 27 --------------------------- iptables/nft-shared.h | 4 ---- iptables/xshared.c | 27 ++++++++++++++++++++++++++- iptables/xshared.h | 4 +++- 8 files changed, 37 insertions(+), 76 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 5c118626..e0cc4e89 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -329,25 +329,8 @@ print_firewall(const struct ip6t_entry *fw, t = ip6t_get_target((struct ip6t_entry *)fw); - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(fw->counters.pcnt, format); - xtables_print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ipv6.invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ipv6.proto); - } + print_rule_details(num, &fw->counters, targname, fw->ipv6.proto, + fw->ipv6.flags, fw->ipv6.invflags, format); if (format & FMT_OPTIONS) { if (format & FMT_NOTABLE) diff --git a/iptables/iptables.c b/iptables/iptables.c index 0d8beb04..29da40b1 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -322,25 +322,8 @@ print_firewall(const struct ipt_entry *fw, t = ipt_get_target((struct ipt_entry *)fw); flags = fw->ip.flags; - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(fw->counters.pcnt, format); - xtables_print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ip.proto); - } + print_rule_details(num, &fw->counters, targname, fw->ip.proto, + fw->ip.flags, fw->ip.invflags, format); if (format & FMT_OPTIONS) { if (format & FMT_NOTABLE) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index dcc009cf..6b044642 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -246,8 +246,8 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_rule_to_iptables_command_state(h, r, &cs); - print_rule_details(&cs, cs.jumpto, cs.fw.ip.flags, - cs.fw.ip.invflags, cs.fw.ip.proto, num, format); + print_rule_details(num, &cs.counters, cs.jumpto, cs.fw.ip.proto, + cs.fw.ip.flags, cs.fw.ip.invflags, format); print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format); print_ifaces(cs.fw.ip.iniface, cs.fw.ip.outiface, cs.fw.ip.invflags, format); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 0b35e045..cb83f9e1 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -198,9 +198,8 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_rule_to_iptables_command_state(h, r, &cs); - print_rule_details(&cs, cs.jumpto, cs.fw6.ipv6.flags, - cs.fw6.ipv6.invflags, cs.fw6.ipv6.proto, - num, format); + print_rule_details(num, &cs.counters, cs.jumpto, cs.fw6.ipv6.proto, + cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format); if (format & FMT_OPTIONS) { if (format & FMT_NOTABLE) fputs("opt ", stdout); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 168c2246..eb007007 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -758,33 +758,6 @@ void print_header(unsigned int format, const char *chain, const char *pol, printf("\n"); } -void print_rule_details(const struct iptables_command_state *cs, - const char *targname, uint8_t flags, - uint8_t invflags, uint8_t proto, - unsigned int num, unsigned int format) -{ - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(cs->counters.pcnt, format); - xtables_print_num(cs->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname ? targname : ""); - - fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = - proto_to_name(proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), proto); - } -} - void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) { const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index cac5757f..e18df20d 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -167,10 +167,6 @@ void nft_clear_iptables_command_state(struct iptables_command_state *cs); void print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, bool basechain, uint32_t refs, uint32_t entries); -void print_rule_details(const struct iptables_command_state *cs, - const char *targname, uint8_t flags, - uint8_t invflags, uint8_t proto, - unsigned int num, unsigned int format); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); diff --git a/iptables/xshared.c b/iptables/xshared.c index 3e06960f..7f2e1a32 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -48,7 +48,7 @@ void print_extension_helps(const struct xtables_target *t, } } -const char * +static const char * proto_to_name(uint16_t proto, int nolookup) { unsigned int i; @@ -999,6 +999,31 @@ void parse_chain(const char *chainname) "Invalid chain name `%s'", chainname); } +void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, + const char *targname, uint8_t proto, uint8_t flags, + uint8_t invflags, unsigned int format) +{ + const char *pname = proto_to_name(proto, format&FMT_NUMERIC); + + if (format & FMT_LINENUMBERS) + printf(FMT("%-4u ", "%u "), linenum); + + if (!(format & FMT_NOCOUNTS)) { + xtables_print_num(ctrs->pcnt, format); + xtables_print_num(ctrs->bcnt, format); + } + + if (!(format & FMT_NOTARGET)) + printf(FMT("%-9s ", "%s "), targname ? targname : ""); + + fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); + + if (pname) + printf(FMT("%-5s", "%s "), pname); + else + printf(FMT("%-5hu", "%hu "), proto); +} + void save_rule_details(const char *iniface, unsigned const char *iniface_mask, const char *outiface, unsigned const char *outiface_mask, uint16_t proto, int frag, uint8_t invflags) diff --git a/iptables/xshared.h b/iptables/xshared.h index 46ad5a29..9f0fa143 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -164,7 +164,6 @@ enum { extern void print_extension_helps(const struct xtables_target *, const struct xtables_rule_match *); -extern const char *proto_to_name(uint16_t, int); extern int command_default(struct iptables_command_state *, struct xtables_globals *, bool invert); extern struct xtables_match *load_proto(struct iptables_command_state *); @@ -246,6 +245,9 @@ void parse_chain(const char *chainname); void generic_opt_check(int command, int options); char opt2char(int option); +void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, + const char *targname, uint8_t proto, uint8_t flags, + uint8_t invflags, unsigned int format); void save_rule_details(const char *iniface, unsigned const char *iniface_mask, const char *outiface, unsigned const char *outiface_mask, uint16_t proto, int frag, uint8_t invflags); -- cgit v1.2.3 From a323c28331a4807252b11a7a078dc68af82399ef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Oct 2019 20:06:11 +0200 Subject: xshared: Share print_fragment() with legacy Also add a fake mode to make it suitable for ip6tables. This is required because IPT_F_FRAG value clashes with IP6T_F_PROTO, so ip6tables rules might seem to have IPT_F_FRAG bit set. While being at it, drop the local variable 'flags' from print_firewall(). Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 8 +------- iptables/iptables.c | 10 +--------- iptables/nft-ipv4.c | 15 +-------------- iptables/nft-ipv6.c | 6 +----- iptables/xshared.c | 18 ++++++++++++++++++ iptables/xshared.h | 3 +++ 6 files changed, 25 insertions(+), 35 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index e0cc4e89..3d304d44 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -332,13 +332,7 @@ print_firewall(const struct ip6t_entry *fw, print_rule_details(num, &fw->counters, targname, fw->ipv6.proto, fw->ipv6.flags, fw->ipv6.invflags, format); - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(' ', stdout); /* Invert flag of FRAG */ - fputc(' ', stdout); /* -f */ - fputc(' ', stdout); - } + print_fragment(fw->ipv6.flags, fw->ipv6.invflags, format, true); print_ifaces(fw->ipv6.iniface, fw->ipv6.outiface, fw->ipv6.invflags, format); diff --git a/iptables/iptables.c b/iptables/iptables.c index 29da40b1..12a5423e 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -311,7 +311,6 @@ print_firewall(const struct ipt_entry *fw, { struct xtables_target *target, *tg; const struct xt_entry_target *t; - uint8_t flags; if (!iptc_is_chain(targname, handle)) target = xtables_find_target(targname, XTF_TRY_LOAD); @@ -320,18 +319,11 @@ print_firewall(const struct ipt_entry *fw, XTF_LOAD_MUST_SUCCEED); t = ipt_get_target((struct ipt_entry *)fw); - flags = fw->ip.flags; print_rule_details(num, &fw->counters, targname, fw->ip.proto, fw->ip.flags, fw->ip.invflags, format); - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); - } + print_fragment(fw->ip.flags, fw->ip.invflags, format, false); print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format); diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 6b044642..f3626098 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -226,19 +226,6 @@ static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto, cs->fw.ip.flags |= IPT_F_GOTO; } -static void print_fragment(unsigned int flags, unsigned int invflags, - unsigned int format) -{ - if (!(format & FMT_OPTIONS)) - return; - - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); -} - static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format) { @@ -248,7 +235,7 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, print_rule_details(num, &cs.counters, cs.jumpto, cs.fw.ip.proto, cs.fw.ip.flags, cs.fw.ip.invflags, format); - print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format); + print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format, false); print_ifaces(cs.fw.ip.iniface, cs.fw.ip.outiface, cs.fw.ip.invflags, format); print_ipv4_addresses(&cs.fw, format); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index cb83f9e1..13213088 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -200,11 +200,7 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, print_rule_details(num, &cs.counters, cs.jumpto, cs.fw6.ipv6.proto, cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format); - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputs(" ", stdout); - } + print_fragment(cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format, true); print_ifaces(cs.fw6.ipv6.iniface, cs.fw6.ipv6.outiface, cs.fw6.ipv6.invflags, format); print_ipv6_addresses(&cs.fw6, format); diff --git a/iptables/xshared.c b/iptables/xshared.c index 7f2e1a32..e8c8939c 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -669,6 +669,24 @@ void save_ipv6_addr(char letter, const struct in6_addr *addr, printf("/%d", l); } +void print_fragment(unsigned int flags, unsigned int invflags, + unsigned int format, bool fake) +{ + if (!(format & FMT_OPTIONS)) + return; + + if (format & FMT_NOTABLE) + fputs("opt ", stdout); + + if (fake) { + fputs(" ", stdout); + } else { + fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout); + fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); + } + fputc(' ', stdout); +} + /* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT * have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT * so this function serves for both iptables and ip6tables */ diff --git a/iptables/xshared.h b/iptables/xshared.h index 9f0fa143..48f314ca 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -232,6 +232,9 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, void save_iface(char letter, const char *iface, const unsigned char *mask, int invert); +void print_fragment(unsigned int flags, unsigned int invflags, + unsigned int format, bool fake); + void command_match(struct iptables_command_state *cs, bool invert); const char *xt_parse_target(const char *targetname); void command_jump(struct iptables_command_state *cs, const char *jumpto); -- cgit v1.2.3 From 24f30842d979da464c1c3ef106d2efa66a480735 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 17 Nov 2020 02:49:32 +0100 Subject: xshared: Share print_header() with legacy iptables Legacy iptables fetches the relevant data via libiptc before calling the shared routine which merely prints data as requested. Drop the 'basechain' parameter, instead make sure a policy name is passed only with base chains. Since the function is not shared with ebtables (which uses a very rudimental header instead), this is safe. In order to support legacy iptables' checking of iptc_get_references() return code (printing an error message instead of the reference count), make refs parameter signed and print the error message if it's negative. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 64 ++++++++++----------------------------------------- iptables/iptables.c | 64 ++++++++++----------------------------------------- iptables/nft-arp.c | 7 +++--- iptables/nft-bridge.c | 2 +- iptables/nft-shared.c | 44 ----------------------------------- iptables/nft-shared.h | 7 ++---- iptables/nft.c | 6 ++--- iptables/xshared.c | 46 ++++++++++++++++++++++++++++++++++++ iptables/xshared.h | 3 +++ 9 files changed, 82 insertions(+), 161 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 3d304d44..5a64566e 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -233,56 +233,6 @@ static int is_exthdr(uint16_t proto) proto == IPPROTO_DSTOPTS); } -static void -print_header(unsigned int format, const char *chain, struct xtc_handle *handle) -{ - struct xt_counters counters; - const char *pol = ip6tc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!ip6tc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - static int print_match(const struct xt_entry_match *m, const struct ip6t_ip6 *ip, @@ -662,8 +612,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, if (found) printf("\n"); - if (!rulenum) - print_header(format, this, handle); + if (!rulenum) { + struct xt_counters counters; + unsigned int urefs; + const char *pol; + int refs = - 1; + + pol = ip6tc_get_policy(this, &counters, handle); + if (!pol && ip6tc_get_references(&urefs, this, handle)) + refs = urefs; + + print_header(format, this, pol, &counters, refs, 0); + } i = ip6tc_first_rule(this, handle); num = 0; diff --git a/iptables/iptables.c b/iptables/iptables.c index 12a5423e..ac51c612 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -224,56 +224,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static void -print_header(unsigned int format, const char *chain, struct xtc_handle *handle) -{ - struct xt_counters counters; - const char *pol = iptc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!iptc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - static int print_match(const struct xt_entry_match *m, const struct ipt_ip *ip, @@ -652,8 +602,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, if (found) printf("\n"); - if (!rulenum) - print_header(format, this, handle); + if (!rulenum) { + struct xt_counters counters; + unsigned int urefs; + const char *pol; + int refs = -1; + + pol = iptc_get_policy(this, &counters, handle); + if (!pol && iptc_get_references(&urefs, this, handle)) + refs = urefs; + + print_header(format, this, pol, &counters, refs, 0); + } i = iptc_first_rule(this, handle); num = 0; diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b7536e61..b211a309 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -308,11 +308,10 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, static void nft_arp_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, - bool basechain, uint32_t refs, - uint32_t entries) + int refs, uint32_t entries) { printf("Chain %s", chain); - if (basechain && pol) { + if (pol) { printf(" (policy %s", pol); if (!(format & FMT_NOCOUNTS)) { fputc(' ', stdout); @@ -323,7 +322,7 @@ static void nft_arp_print_header(unsigned int format, const char *chain, } printf(")\n"); } else { - printf(" (%u references)\n", refs); + printf(" (%d references)\n", refs); } } diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index cc2a48db..5cde302c 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -534,7 +534,7 @@ static void nft_bridge_print_table_header(const char *tablename) static void nft_bridge_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, - bool basechain, uint32_t refs, uint32_t entries) + int refs, uint32_t entries) { printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, entries, pol ?: "RETURN"); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index eb007007..a6a79c8c 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -714,50 +714,6 @@ void nft_clear_iptables_command_state(struct iptables_command_state *cs) } } -void print_header(unsigned int format, const char *chain, const char *pol, - const struct xt_counters *counters, bool basechain, - uint32_t refs, uint32_t entries) -{ - printf("Chain %s", chain); - if (basechain) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters->pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters->bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) { const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index e18df20d..de684374 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -94,8 +94,8 @@ struct nft_family_ops { void (*print_table_header)(const char *tablename); void (*print_header)(unsigned int format, const char *chain, const char *pol, - const struct xt_counters *counters, bool basechain, - uint32_t refs, uint32_t entries); + const struct xt_counters *counters, + int refs, uint32_t entries); void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format); void (*save_rule)(const void *data, unsigned int format); @@ -164,9 +164,6 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void nft_clear_iptables_command_state(struct iptables_command_state *cs); -void print_header(unsigned int format, const char *chain, const char *pol, - const struct xt_counters *counters, bool basechain, - uint32_t refs, uint32_t entries); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); diff --git a/iptables/nft.c b/iptables/nft.c index 282d417f..887c735b 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2398,7 +2398,6 @@ static void __nft_print_header(struct nft_handle *h, { struct nftnl_chain *c = nc->nftnl; 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 = { @@ -2407,11 +2406,12 @@ static void __nft_print_header(struct nft_handle *h, }; const char *pname = NULL; - if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) + if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) && + nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)]; h->ops->print_header(format, chain_name, pname, - &ctrs, basechain, refs - entries, entries); + &ctrs, refs - entries, entries); } struct nft_rule_list_cb_data { diff --git a/iptables/xshared.c b/iptables/xshared.c index e8c8939c..37ea7106 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -547,6 +547,52 @@ void debug_print_argv(struct argv_store *store) } #endif +void print_header(unsigned int format, const char *chain, const char *pol, + const struct xt_counters *counters, + int refs, uint32_t entries) +{ + printf("Chain %s", chain); + if (pol) { + printf(" (policy %s", pol); + if (!(format & FMT_NOCOUNTS)) { + fputc(' ', stdout); + xtables_print_num(counters->pcnt, (format|FMT_NOTABLE)); + fputs("packets, ", stdout); + xtables_print_num(counters->bcnt, (format|FMT_NOTABLE)); + fputs("bytes", stdout); + } + printf(")\n"); + } else if (refs < 0) { + printf(" (ERROR obtaining refs)\n"); + } else { + printf(" (%d references)\n", refs); + } + + if (format & FMT_LINENUMBERS) + printf(FMT("%-4s ", "%s "), "num"); + if (!(format & FMT_NOCOUNTS)) { + if (format & FMT_KILOMEGAGIGA) { + printf(FMT("%5s ","%s "), "pkts"); + printf(FMT("%5s ","%s "), "bytes"); + } else { + printf(FMT("%8s ","%s "), "pkts"); + printf(FMT("%10s ","%s "), "bytes"); + } + } + if (!(format & FMT_NOTARGET)) + printf(FMT("%-9s ","%s "), "target"); + fputs(" prot ", stdout); + if (format & FMT_OPTIONS) + fputs("opt", stdout); + if (format & FMT_VIA) { + printf(FMT(" %-6s ","%s "), "in"); + printf(FMT("%-6s ","%s "), "out"); + } + printf(FMT(" %-19s ","%s "), "source"); + printf(FMT(" %-19s "," %s "), "destination"); + printf("\n"); +} + const char *ipv4_addr_to_string(const struct in_addr *addr, const struct in_addr *mask, unsigned int format) diff --git a/iptables/xshared.h b/iptables/xshared.h index 48f314ca..75794009 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -220,6 +220,9 @@ void debug_print_argv(struct argv_store *store); const char *ipv4_addr_to_string(const struct in_addr *addr, const struct in_addr *mask, unsigned int format); +void print_header(unsigned int format, const char *chain, const char *pol, + const struct xt_counters *counters, + int refs, uint32_t entries); void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format); void save_ipv4_addr(char letter, const struct in_addr *addr, const struct in_addr *mask, int invert); -- cgit v1.2.3 From cf14b92bc1a3f5040437234dffe5cf6aa59711a5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 6 Nov 2021 01:09:37 +0100 Subject: nft-shared: Drop unused function print_proto() The last users vanished back in 2013. There is identical code in save_rule_details(), but with only a single user there's not much point in keeping the function. Fixes: cdc78b1d6bd7b ("nft: convert rule into a command state structure") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 15 --------------- iptables/nft-shared.h | 1 - 2 files changed, 16 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index a6a79c8c..b281ba29 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -373,21 +373,6 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->h->ops->parse_match(match, ctx->cs); } -void print_proto(uint16_t proto, int invert) -{ - const struct protoent *pent = getprotobynumber(proto); - - if (invert) - printf("! "); - - if (pent) { - printf("-p %s ", pent->p_name); - return; - } - - printf("-p %u ", proto); -} - void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) { uint32_t len; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index de684374..bcf8486e 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -158,7 +158,6 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, 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_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, -- cgit v1.2.3 From 7213561d9d7a17c4db29c867b2607241941dae5a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 6 Nov 2021 01:32:47 +0100 Subject: xshared: Make load_proto() static The last outside users vanished ten years ago. Fixes: 449cdd6bcc8d1 ("src: combine default_command functions") Signed-off-by: Phil Sutter --- iptables/xshared.c | 2 +- iptables/xshared.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 37ea7106..a1ca2b0f 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -107,7 +107,7 @@ static bool should_load_proto(struct iptables_command_state *cs) return !cs->proto_used; } -struct xtables_match *load_proto(struct iptables_command_state *cs) +static struct xtables_match *load_proto(struct iptables_command_state *cs) { if (!should_load_proto(cs)) return NULL; diff --git a/iptables/xshared.h b/iptables/xshared.h index 75794009..060c62ef 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -166,7 +166,6 @@ extern void print_extension_helps(const struct xtables_target *, const struct xtables_rule_match *); extern int command_default(struct iptables_command_state *, struct xtables_globals *, bool invert); -extern struct xtables_match *load_proto(struct iptables_command_state *); extern int subcmd_main(int, char **, const struct subcommand *); extern void xs_init_target(struct xtables_target *); extern void xs_init_match(struct xtables_match *); -- cgit v1.2.3 From 273d88a7744ea5638969ad3252acf518e5ec6cc2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 28 Nov 2021 18:25:53 +0100 Subject: extensions: tcpmss: add iptables-translate support Signed-off-by: Florian Westphal --- extensions/libxt_tcpmss.c | 16 ++++++++++++++++ extensions/libxt_tcpmss.txlate | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 extensions/libxt_tcpmss.txlate diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c index bcd357aa..61b853d1 100644 --- a/extensions/libxt_tcpmss.c +++ b/extensions/libxt_tcpmss.c @@ -60,6 +60,21 @@ static void tcpmss_save(const void *ip, const struct xt_entry_match *match) printf("%u:%u", info->mss_min, info->mss_max); } +static int tcpmss_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_tcpmss_match_info *info = (void *)params->match->data; + + xt_xlate_add(xl, "tcp option maxseg size %s", info->invert ? "!= " : ""); + + if (info->mss_min == info->mss_max) + xt_xlate_add(xl, "%u", info->mss_min); + else + xt_xlate_add(xl, "%u-%u", info->mss_min, info->mss_max); + + return 1; +} + static struct xtables_match tcpmss_match = { .family = NFPROTO_UNSPEC, .name = "tcpmss", @@ -71,6 +86,7 @@ static struct xtables_match tcpmss_match = { .save = tcpmss_save, .x6_parse = tcpmss_parse, .x6_options = tcpmss_opts, + .xlate = tcpmss_xlate, }; void _init(void) diff --git a/extensions/libxt_tcpmss.txlate b/extensions/libxt_tcpmss.txlate new file mode 100644 index 00000000..d3f1b27d --- /dev/null +++ b/extensions/libxt_tcpmss.txlate @@ -0,0 +1,11 @@ +iptables-translate -A INPUT -m tcpmss --mss 42 +nft add rule ip filter INPUT tcp option maxseg size 42 counter + +iptables-translate -A INPUT -m tcpmss ! --mss 42 +nft add rule ip filter INPUT tcp option maxseg size != 42 counter + +iptables-translate -A INPUT -m tcpmss --mss 42:1024 +nft add rule ip filter INPUT tcp option maxseg size 42-1024 counter + +iptables-translate -A INPUT -m tcpmss ! --mss 1461:65535 +nft add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter -- cgit v1.2.3 From 4149b5d836340c744c78f303e2a877a89c271000 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 21 Oct 2021 03:00:57 +0200 Subject: xshared: Share print_match_save() between legacy ip*tables The only difference between the former two copies was the type of ip*_entry parameter. But since it is treated opaque, just hide that detail by casting to void. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 31 ------------------------------- iptables/iptables.c | 31 ------------------------------- iptables/xshared.c | 30 ++++++++++++++++++++++++++++++ iptables/xshared.h | 2 ++ 4 files changed, 32 insertions(+), 62 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 5a64566e..0509c36c 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -644,37 +644,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -static int print_match_save(const struct xt_entry_match *e, - const struct ip6t_ip6 *ip) -{ - const char *name = e->u.user.name; - const int revision = e->u.user.revision; - struct xtables_match *match, *mt, *mt2; - - match = xtables_find_match(name, XTF_TRY_LOAD, NULL); - if (match) { - mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, - match, revision); - if (!mt2) - mt2 = match; - printf(" -m %s", mt2->alias ? mt2->alias(e) : name); - - /* some matches don't provide a save function */ - if (mt && mt->save) - mt->save(ip, e); - else if (match->save) - printf(unsupported_rev); - } else { - if (e->u.match_size) { - fprintf(stderr, - "Can't find library for match `%s'\n", - name); - exit(1); - } - } - return 0; -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ diff --git a/iptables/iptables.c b/iptables/iptables.c index ac51c612..a69d4238 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -642,37 +642,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) -static int print_match_save(const struct xt_entry_match *e, - const struct ipt_ip *ip) -{ - const char *name = e->u.user.name; - const int revision = e->u.user.revision; - struct xtables_match *match, *mt, *mt2; - - match = xtables_find_match(name, XTF_TRY_LOAD, NULL); - if (match) { - mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, - match, revision); - if (!mt2) - mt2 = match; - printf(" -m %s", mt2->alias ? mt2->alias(e) : name); - - /* some matches don't provide a save function */ - if (mt && mt->save) - mt->save(ip, e); - else if (match->save) - printf(unsupported_rev); - } else { - if (e->u.match_size) { - fprintf(stderr, - "Can't find library for match `%s'\n", - name); - exit(1); - } - } - return 0; -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ diff --git a/iptables/xshared.c b/iptables/xshared.c index a1ca2b0f..94a2d088 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1119,3 +1119,33 @@ void save_rule_details(const char *iniface, unsigned const char *iniface_mask, printf(" -f"); } } + +int print_match_save(const struct xt_entry_match *e, const void *ip) +{ + const char *name = e->u.user.name; + const int revision = e->u.user.revision; + struct xtables_match *match, *mt, *mt2; + + match = xtables_find_match(name, XTF_TRY_LOAD, NULL); + if (match) { + mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, + match, revision); + if (!mt2) + mt2 = match; + printf(" -m %s", mt2->alias ? mt2->alias(e) : name); + + /* some matches don't provide a save function */ + if (mt && mt->save) + mt->save(ip, e); + else if (match->save) + printf(" [unsupported revision]"); + } else { + if (e->u.match_size) { + fprintf(stderr, + "Can't find library for match `%s'\n", + name); + exit(1); + } + } + return 0; +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 060c62ef..1ee64d9e 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -257,4 +257,6 @@ void save_rule_details(const char *iniface, unsigned const char *iniface_mask, const char *outiface, unsigned const char *outiface_mask, uint16_t proto, int frag, uint8_t invflags); +int print_match_save(const struct xt_entry_match *e, const void *ip); + #endif /* IPTABLES_XSHARED_H */ -- cgit v1.2.3 From 56ac0452a4968f1af8d3ad1717c8646593177155 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 21 Oct 2021 13:04:45 +0200 Subject: xshared: Share a common printhelp function Help texts in legacy and nft variants are supposed to be identical, but those of iptables and ip6tables largely overlapped already. By referring to xt_params and afinfo pointers, it is relatively trivial to craft a suitable help text on demand, so duplicated help texts can be eliminated. As a side-effect, this fixes ip6tables-nft help text - it was identical to that of iptables-nft. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 79 +-------------------------------------- iptables/iptables.c | 78 +------------------------------------- iptables/xshared.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ iptables/xshared.h | 2 + iptables/xtables.c | 85 +----------------------------------------- 5 files changed, 108 insertions(+), 239 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 0509c36c..46f7785b 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -114,84 +114,7 @@ exit_tryhelp(int status) static void exit_printhelp(const struct xtables_rule_match *matches) { - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - prog_name, prog_vers, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n" -" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n" -"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" -"[!] --source -s address[/mask][,...]\n" -" source specification\n" -"[!] --destination -d address[/mask][,...]\n" -" destination specification\n" -"[!] --in-interface -i input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -#ifdef IP6T_F_GOTO -" --goto -g chain\n" -" jump to chain with no return\n" -#endif -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -"[!] --out-interface -o output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" interval to wait for xtables lock\n" -" default is 1 second\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -/*"[!] --fragment -f match second or further fragments only\n"*/ -" --modprobe= try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); - - print_extension_helps(xtables_targets, matches); + xtables_printhelp(matches); exit(0); } diff --git a/iptables/iptables.c b/iptables/iptables.c index a69d4238..7b450349 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -112,83 +112,7 @@ exit_tryhelp(int status) static void exit_printhelp(const struct xtables_rule_match *matches) { - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - prog_name, prog_vers, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n" -" --ipv6 -6 Error (line is ignored by iptables-restore)\n" -"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" -"[!] --source -s address[/mask][...]\n" -" source specification\n" -"[!] --destination -d address[/mask][...]\n" -" destination specification\n" -"[!] --in-interface -i input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -#ifdef IPT_F_GOTO -" --goto -g chain\n" -" jump to chain with no return\n" -#endif -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -"[!] --out-interface -o output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" default is 1 second\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); - - print_extension_helps(xtables_targets, matches); + xtables_printhelp(matches); exit(0); } diff --git a/iptables/xshared.c b/iptables/xshared.c index 94a2d088..9b326107 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1149,3 +1149,106 @@ int print_match_save(const struct xt_entry_match *e, const void *ip) } return 0; } + +void +xtables_printhelp(const struct xtables_rule_match *matches) +{ + const char *prog_name = xt_params->program_name; + const char *prog_vers = xt_params->program_version; + + printf("%s v%s\n\n" +"Usage: %s -[ACD] chain rule-specification [options]\n" +" %s -I chain [rulenum] rule-specification [options]\n" +" %s -R chain rulenum rule-specification [options]\n" +" %s -D chain rulenum [options]\n" +" %s -[LS] [chain [rulenum]] [options]\n" +" %s -[FZ] [chain] [options]\n" +" %s -[NX] chain\n" +" %s -E old-chain-name new-chain-name\n" +" %s -P chain target [options]\n" +" %s -h (print this help information)\n\n", + prog_name, prog_vers, prog_name, prog_name, + prog_name, prog_name, prog_name, prog_name, + prog_name, prog_name, prog_name, prog_name); + + printf( +"Commands:\n" +"Either long or short options are allowed.\n" +" --append -A chain Append to chain\n" +" --check -C chain Check for the existence of a rule\n" +" --delete -D chain Delete matching rule from chain\n" +" --delete -D chain rulenum\n" +" Delete rule rulenum (1 = first) from chain\n" +" --insert -I chain [rulenum]\n" +" Insert in chain as rulenum (default 1=first)\n" +" --replace -R chain rulenum\n" +" Replace rule rulenum (1 = first) in chain\n" +" --list -L [chain [rulenum]]\n" +" List the rules in a chain or all chains\n" +" --list-rules -S [chain [rulenum]]\n" +" Print the rules in a chain or all chains\n" +" --flush -F [chain] Delete all rules in chain or all chains\n" +" --zero -Z [chain [rulenum]]\n" +" Zero counters in chain or all chains\n" +" --new -N chain Create a new user-defined chain\n" +" --delete-chain\n" +" -X [chain] Delete a user-defined chain\n" +" --policy -P chain target\n" +" Change policy on chain to target\n" +" --rename-chain\n" +" -E old-chain new-chain\n" +" Change chain name, (moving any references)\n"); + + printf( +"Options:\n" +" --ipv4 -4 %s (line is ignored by ip6tables-restore)\n" +" --ipv6 -6 %s (line is ignored by iptables-restore)\n" +"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" +"[!] --source -s address[/mask][...]\n" +" source specification\n" +"[!] --destination -d address[/mask][...]\n" +" destination specification\n" +"[!] --in-interface -i input name[+]\n" +" network interface name ([+] for wildcard)\n" +" --jump -j target\n" +" target for rule (may load target extension)\n", + afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error", + afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing"); + + if (0 +#ifdef IPT_F_GOTO + || afinfo->family == NFPROTO_IPV4 +#endif +#ifdef IP6T_F_GOTO + || afinfo->family == NFPROTO_IPV6 +#endif + ) + printf( +" --goto -g chain\n" +" jump to chain with no return\n"); + printf( +" --match -m match\n" +" extended match (may load extension)\n" +" --numeric -n numeric output of addresses and ports\n" +"[!] --out-interface -o output name[+]\n" +" network interface name ([+] for wildcard)\n" +" --table -t table table to manipulate (default: `filter')\n" +" --verbose -v verbose mode\n" +" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" +" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" +" interval to wait for xtables lock\n" +" default is 1 second\n" +" --line-numbers print line numbers when listing\n" +" --exact -x expand numbers (display exact values)\n"); + + if (afinfo->family == NFPROTO_IPV4) + printf( +"[!] --fragment -f match second or further fragments only\n"); + + printf( +" --modprobe= try to insert modules using this command\n" +" --set-counters PKTS BYTES set the counter during insert/append\n" +"[!] --version -V print package version.\n"); + + print_extension_helps(xtables_targets, matches); +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 1ee64d9e..3310954c 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -259,4 +259,6 @@ void save_rule_details(const char *iniface, unsigned const char *iniface_mask, int print_match_save(const struct xt_entry_match *e, const void *ip); +void xtables_printhelp(const struct xtables_rule_match *matches); + #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables.c b/iptables/xtables.c index 32b93d2b..36324a5d 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -87,7 +87,6 @@ static struct option original_opts[] = { }; void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); -static void printhelp(const struct xtables_rule_match *m); struct xtables_globals xtables_globals = { .option_offset = 0, @@ -96,7 +95,7 @@ struct xtables_globals xtables_globals = { .orig_opts = original_opts, .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, - .print_help = printhelp, + .print_help = xtables_printhelp, }; #define opts xt_params->opts @@ -114,88 +113,6 @@ exit_tryhelp(int status) exit(status); } -static void -printhelp(const struct xtables_rule_match *matches) -{ - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - prog_name, prog_vers, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n" -" --ipv6 -6 Error (line is ignored by iptables-restore)\n" -"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n" -"[!] --source -s address[/mask][...]\n" -" source specification\n" -"[!] --destination -d address[/mask][...]\n" -" destination specification\n" -"[!] --in-interface -i input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -#ifdef IPT_F_GOTO -" --goto -g chain\n" -" jump to chain with no return\n" -#endif -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -"[!] --out-interface -o output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" default is 1 second\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); - - print_extension_helps(xtables_targets, matches); -} - void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) { -- cgit v1.2.3 From 51e5d29357644965bc6a8a4d1f3b2878936147f7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 27 Nov 2021 00:18:28 +0100 Subject: xshared: Share exit_tryhelp() The function existed three times in identical form. Avoid having to declare extern int line in xshared.c by making it a parameter. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 19 ++++--------------- iptables/iptables.c | 19 ++++--------------- iptables/xshared.c | 10 ++++++++++ iptables/xshared.h | 1 + iptables/xtables.c | 21 +++++---------------- 5 files changed, 24 insertions(+), 46 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 46f7785b..788966d6 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -100,17 +100,6 @@ struct xtables_globals ip6tables_globals = { #define prog_name ip6tables_globals.program_name #define prog_vers ip6tables_globals.program_version -static void __attribute__((noreturn)) -exit_tryhelp(int status) -{ - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - prog_name, prog_name); - xtables_free_opts(1); - exit(status); -} - static void exit_printhelp(const struct xtables_rule_match *matches) { @@ -129,7 +118,7 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) va_end(args); fprintf(stderr, "\n"); if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); + exit_tryhelp(status, line); if (status == VERSION_PROBLEM) fprintf(stderr, "Perhaps ip6tables or your kernel needs to be upgraded.\n"); @@ -1106,7 +1095,7 @@ int do_command6(int argc, char *argv[], char **table, if (line != -1) return 1; /* success: line ignored */ fprintf(stderr, "This is the IPv6 version of ip6tables.\n"); - exit_tryhelp(2); + exit_tryhelp(2, line); case '6': /* This is indeed the IPv6 ip6tables */ @@ -1123,7 +1112,7 @@ int do_command6(int argc, char *argv[], char **table, continue; } fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2); + exit_tryhelp(2, line); default: if (command_default(&cs, &ip6tables_globals, invert)) @@ -1372,7 +1361,7 @@ int do_command6(int argc, char *argv[], char **table, break; default: /* We should never reach this... */ - exit_tryhelp(2); + exit_tryhelp(2, line); } if (verbose > 1) diff --git a/iptables/iptables.c b/iptables/iptables.c index 7b450349..78fff9ef 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -98,17 +98,6 @@ struct xtables_globals iptables_globals = { #define prog_name iptables_globals.program_name #define prog_vers iptables_globals.program_version -static void __attribute__((noreturn)) -exit_tryhelp(int status) -{ - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - prog_name, prog_name); - xtables_free_opts(1); - exit(status); -} - static void exit_printhelp(const struct xtables_rule_match *matches) { @@ -127,7 +116,7 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...) va_end(args); fprintf(stderr, "\n"); if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); + exit_tryhelp(status, line); if (status == VERSION_PROBLEM) fprintf(stderr, "Perhaps iptables or your kernel needs to be upgraded.\n"); @@ -1093,7 +1082,7 @@ int do_command4(int argc, char *argv[], char **table, if (line != -1) return 1; /* success: line ignored */ fprintf(stderr, "This is the IPv4 version of iptables.\n"); - exit_tryhelp(2); + exit_tryhelp(2, line); case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { @@ -1106,7 +1095,7 @@ int do_command4(int argc, char *argv[], char **table, continue; } fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2); + exit_tryhelp(2, line); default: if (command_default(&cs, &iptables_globals, invert)) @@ -1353,7 +1342,7 @@ int do_command4(int argc, char *argv[], char **table, break; default: /* We should never reach this... */ - exit_tryhelp(2); + exit_tryhelp(2, line); } if (verbose > 1) diff --git a/iptables/xshared.c b/iptables/xshared.c index 9b326107..efee7a30 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1252,3 +1252,13 @@ xtables_printhelp(const struct xtables_rule_match *matches) print_extension_helps(xtables_targets, matches); } + +void exit_tryhelp(int status, int line) +{ + if (line != -1) + fprintf(stderr, "Error occurred at line: %d\n", line); + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + xt_params->program_name, xt_params->program_name); + xtables_free_opts(1); + exit(status); +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 3310954c..2c05b0d7 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -260,5 +260,6 @@ void save_rule_details(const char *iniface, unsigned const char *iniface_mask, int print_match_save(const struct xt_entry_match *e, const void *ip); void xtables_printhelp(const struct xtables_rule_match *matches); +void exit_tryhelp(int status, int line) __attribute__((noreturn)); #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables.c b/iptables/xtables.c index 36324a5d..d53fd758 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -102,17 +102,6 @@ struct xtables_globals xtables_globals = { #define prog_name xt_params->program_name #define prog_vers xt_params->program_version -static void __attribute__((noreturn)) -exit_tryhelp(int status) -{ - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - prog_name, prog_name); - xtables_free_opts(1); - exit(status); -} - void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) { @@ -124,7 +113,7 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) va_end(args); fprintf(stderr, "\n"); if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); + exit_tryhelp(status, line); if (status == VERSION_PROBLEM) fprintf(stderr, "Perhaps iptables or your kernel needs to be upgraded.\n"); @@ -631,7 +620,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], if (p->restore && args->family == AF_INET6) return; - exit_tryhelp(2); + exit_tryhelp(2, line); case '6': if (args->family == AF_INET6) @@ -640,7 +629,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], if (p->restore && args->family == AF_INET) return; - exit_tryhelp(2); + exit_tryhelp(2, line); case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { @@ -653,7 +642,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], continue; } fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2); + exit_tryhelp(2, line); default: if (command_default(cs, xt_params, invert)) @@ -849,7 +838,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, break; default: /* We should never reach this... */ - exit_tryhelp(2); + exit_tryhelp(2, line); } *table = p.table; -- cgit v1.2.3 From 4bff5aef6e63fb4d403d539f4c9d2d90492120b8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 16:53:31 +0100 Subject: xtables_globals: Embed variant name in .program_version Both are constant strings, so precompiler may concat them. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 6 +++--- iptables/iptables-restore.c | 2 +- iptables/iptables-save.c | 2 +- iptables/iptables.c | 6 +++--- iptables/xtables-arp.c | 2 +- iptables/xtables-eb.c | 4 ++-- iptables/xtables-restore.c | 2 +- iptables/xtables-save.c | 2 +- iptables/xtables.c | 6 +++--- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 788966d6..44d2c08c 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -90,7 +90,7 @@ static struct option original_opts[] = { void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals ip6tables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, .exit_err = ip6tables_exit_error, .compat_rev = xtables_compatible_revision, @@ -113,7 +113,7 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) va_list args; va_start(args, msg); - fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers); + fprintf(stderr, "%s v%s: ", prog_name, prog_vers); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -1049,7 +1049,7 @@ int do_command6(int argc, char *argv[], char **table, if (invert) printf("Not %s ;-)\n", prog_vers); else - printf("%s v%s (legacy)\n", + printf("%s v%s\n", prog_name, prog_vers); exit(0); diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index cc2c2b8b..a3efb067 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -117,7 +117,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, verbose = 1; break; case 'V': - printf("%s v%s (legacy)\n", + printf("%s v%s\n", xt_params->program_name, xt_params->program_version); exit(0); diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index 4efd6667..a114e98b 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -173,7 +173,7 @@ do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[]) do_output(cb, tablename); exit(0); case 'V': - printf("%s v%s (legacy)\n", + printf("%s v%s\n", xt_params->program_name, xt_params->program_version); exit(0); diff --git a/iptables/iptables.c b/iptables/iptables.c index 78fff9ef..191877ec 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -88,7 +88,7 @@ void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __a struct xtables_globals iptables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, .exit_err = iptables_exit_error, .compat_rev = xtables_compatible_revision, @@ -111,7 +111,7 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...) va_list args; va_start(args, msg); - fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers); + fprintf(stderr, "%s v%s: ", prog_name, prog_vers); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -1032,7 +1032,7 @@ int do_command4(int argc, char *argv[], char **table, if (invert) printf("Not %s ;-)\n", prog_vers); else - printf("%s v%s (legacy)\n", + printf("%s v%s\n", prog_name, prog_vers); exit(0); diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index cca19438..8a226330 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -88,7 +88,7 @@ extern void xtables_exit_error(enum xtables_exittype status, const char *msg, .. static void printhelp(const struct xtables_rule_match *m); struct xtables_globals arptables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, .exit_err = xtables_exit_error, diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 3f58754d..604d4d39 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -219,7 +219,7 @@ struct option ebt_original_options[] = 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 = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "h", .orig_opts = ebt_original_options, .exit_err = xtables_exit_error, @@ -860,7 +860,7 @@ print_zero: if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "Multiple commands are not allowed"); - printf("%s %s (nf_tables)\n", prog_name, prog_vers); + printf("%s %s\n", prog_name, prog_vers); exit(0); case 'h': /* Help */ if (OPT_COMMANDS) diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index aa8b397f..8ca2abff 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -312,7 +312,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) verbose = 1; break; case 'V': - printf("%s v%s (nf_tables)\n", prog_name, prog_vers); + printf("%s v%s\n", prog_name, prog_vers); exit(0); case 't': p.testing = 1; diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index c6ebb0ec..03d2b980 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -184,7 +184,7 @@ xtables_save_main(int family, int argc, char *argv[], dump = true; break; case 'V': - printf("%s v%s (nf_tables)\n", prog_name, prog_vers); + printf("%s v%s\n", prog_name, prog_vers); exit(0); default: fprintf(stderr, diff --git a/iptables/xtables.c b/iptables/xtables.c index d53fd758..a6b10cf8 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -90,7 +90,7 @@ void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __at struct xtables_globals xtables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .exit_err = xtables_exit_error, @@ -108,7 +108,7 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...) va_list args; va_start(args, msg); - fprintf(stderr, "%s v%s (nf_tables): ", prog_name, prog_vers); + fprintf(stderr, "%s v%s: ", prog_name, prog_vers); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -554,7 +554,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], if (invert) printf("Not %s ;-)\n", prog_vers); else - printf("%s v%s (nf_tables)\n", + printf("%s v%s\n", prog_name, prog_vers); exit(0); -- cgit v1.2.3 From 316d8efbb7cd2d252c8627df77261a466493d09b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 21:11:25 +0100 Subject: libxtables: Extend basic_exit_err() Basically merge the function with xtables_exit_error, printing a status-specific footer for parameter or version problems. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 22 ---------------------- iptables/iptables.c | 23 ----------------------- iptables/xtables-arp.c | 2 -- iptables/xtables-eb.c | 2 -- iptables/xtables.c | 23 ----------------------- libxtables/xtables.c | 12 ++++++++++++ 6 files changed, 12 insertions(+), 72 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 44d2c08c..2f3ff034 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -87,12 +87,10 @@ static struct option original_opts[] = { {NULL}, }; -void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals ip6tables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, - .exit_err = ip6tables_exit_error, .compat_rev = xtables_compatible_revision, }; @@ -107,26 +105,6 @@ exit_printhelp(const struct xtables_rule_match *matches) exit(0); } -void -ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", prog_name, prog_vers); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status, line); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps ip6tables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - xtables_free_opts(1); - exit(status); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. diff --git a/iptables/iptables.c b/iptables/iptables.c index 191877ec..ba04fbc6 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -84,13 +84,10 @@ static struct option original_opts[] = { {NULL}, }; -void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); - struct xtables_globals iptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, - .exit_err = iptables_exit_error, .compat_rev = xtables_compatible_revision, }; @@ -105,26 +102,6 @@ exit_printhelp(const struct xtables_rule_match *matches) exit(0); } -void -iptables_exit_error(enum xtables_exittype status, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", prog_name, prog_vers); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status, line); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps iptables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - xtables_free_opts(1); - exit(status); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 8a226330..805fb19a 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -84,14 +84,12 @@ static struct option original_opts[] = { #define opts xt_params->opts -extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); static void printhelp(const struct xtables_rule_match *m); struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, - .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, .print_help = printhelp, }; diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 604d4d39..ed8f7332 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -216,13 +216,11 @@ struct option ebt_original_options[] = { 0 } }; -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 = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "h", .orig_opts = ebt_original_options, - .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, }; diff --git a/iptables/xtables.c b/iptables/xtables.c index a6b10cf8..5255fa34 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -86,14 +86,11 @@ static struct option original_opts[] = { {NULL}, }; -void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); - struct xtables_globals xtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, - .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, .print_help = xtables_printhelp, }; @@ -102,26 +99,6 @@ struct xtables_globals xtables_globals = { #define prog_name xt_params->program_name #define prog_vers xt_params->program_version -void -xtables_exit_error(enum xtables_exittype status, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", prog_name, prog_vers); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status, line); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps iptables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - xtables_free_opts(1); - exit(status); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. diff --git a/libxtables/xtables.c b/libxtables/xtables.c index d670175d..50fd6a44 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -90,6 +90,18 @@ void basic_exit_err(enum xtables_exittype status, const char *msg, ...) vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) { + if (line != -1) + fprintf(stderr, "Error occurred at line: %d\n", line); + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + xt_params->program_name, xt_params->program_name); + } else if (status == VERSION_PROBLEM) { + fprintf(stderr, + "Perhaps %s or your kernel needs to be upgraded.\n", + xt_params->program_name); + } + /* On error paths, make sure that we don't leak memory */ + xtables_free_opts(1); exit(status); } -- cgit v1.2.3 From b129b1cfcdbc82430cbbb90e83c344a14e77a808 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 21:45:12 +0100 Subject: iptables-*-restore: Drop pointless line reference There's no need to mention the offending line number in error message when calling xtables_error() with a status of PARAMETER_PROBLEM as that will cause a call to xtables_exit_tryhelp() which in turn prints "Error occurred at line: N". Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 4 ++-- iptables/iptables.c | 4 ++-- iptables/xtables-eb.c | 4 ++-- iptables/xtables.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 2f3ff034..b4604f83 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -1012,8 +1012,8 @@ int do_command6(int argc, char *argv[], char **table, "unexpected ! flag before --table"); if (restore && table_set) xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); + "The -t option cannot be used in %s.\n", + xt_params->program_name); *table = optarg; table_set = true; break; diff --git a/iptables/iptables.c b/iptables/iptables.c index ba04fbc6..7dc4cbc1 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -994,8 +994,8 @@ int do_command4(int argc, char *argv[], char **table, "unexpected ! flag before --table"); if (restore && table_set) xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); + "The -t option cannot be used in %s.\n", + xt_params->program_name); *table = optarg; table_set = true; break; diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index ed8f7332..060e06c5 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -894,8 +894,8 @@ print_zero: ebt_check_option2(&flags, OPT_TABLE); if (restore && table_set) xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); + "The -t option cannot be used in %s.\n", + xt_params->program_name); if (!nft_table_builtin_find(h, optarg)) xtables_error(VERSION_PROBLEM, "table '%s' does not exist", diff --git a/iptables/xtables.c b/iptables/xtables.c index 5255fa34..57bec76c 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -512,8 +512,8 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "unexpected ! flag before --table"); if (p->restore && table_set) xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); + "The -t option cannot be used in %s.\n", + xt_params->program_name); if (!nft_table_builtin_find(h, optarg)) xtables_error(VERSION_PROBLEM, "table '%s' does not exist", -- cgit v1.2.3 From 49aa44ba9e09e5f62f3dccbe14b845e20cfc7b20 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 18 Dec 2021 21:14:15 +0100 Subject: nft-shared: set correct register value NFTNL_EXPR_META_DREG equals NFTNL_EXPR_PAYLOAD_BASE, so we set dreg to the payload base instead. It "works" because the simple nft rules currently generated via ipables-nft have base == register-number but this is a coincidence. Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index b281ba29..4394e8b7 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -443,7 +443,7 @@ static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD; } - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); + ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); -- cgit v1.2.3 From d83371c7330632a85a443c09ade2f9e0fac615e4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 18:26:07 +0100 Subject: xtables: Drop xtables' family on demand feature This conditional h->family assignment was added by commit 3f7877e6be987 ("xtables-restore: add -4 and -6 support") with the intention to support something like 'xtables-restore -6 --- iptables/xtables.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iptables/xtables.c b/iptables/xtables.c index 57bec76c..5c48bd94 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -657,10 +657,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); - /* Set only if required, needed by xtables-restore */ - if (h->family == AF_UNSPEC) - h->family = args->family; - h->ops->post_parse(p->command, cs, args); if (p->command == CMD_REPLACE && -- cgit v1.2.3 From 98a4462f0abd54d96ed91d07d55608dd10fec414 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 15:53:14 +0100 Subject: xtables: Pull table validity check out of do_parse() Makes do_parse() more generic, error codes don't change so this should be safe. Signed-off-by: Phil Sutter --- iptables/xtables.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iptables/xtables.c b/iptables/xtables.c index 5c48bd94..ac864eb2 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -514,10 +514,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], xtables_error(PARAMETER_PROBLEM, "The -t option cannot be used in %s.\n", xt_params->program_name); - if (!nft_table_builtin_find(h, optarg)) - xtables_error(VERSION_PROBLEM, - "table '%s' does not exist", - optarg); p->table = optarg; table_set = true; break; @@ -720,6 +716,10 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, do_parse(h, argc, argv, &p, &cs, &args); + if (!nft_table_builtin_find(h, p.table)) + xtables_error(VERSION_PROBLEM, + "table '%s' does not exist", + p.table); switch (p.command) { case CMD_APPEND: ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args, -- cgit v1.2.3 From dc8d8fce581bff4640803f3db07f0c2df5e7e18f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 22 Dec 2021 21:58:18 +0100 Subject: xtables: Move struct nft_xt_cmd_parse to xshared.h Preparing for shared use with legacy variants, move it to "neutral ground" and give it a more generic name. Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 14 +------------- iptables/xshared.h | 12 ++++++++++++ iptables/xtables-eb-translate.c | 4 ++-- iptables/xtables-translate.c | 8 ++++---- iptables/xtables.c | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index bcf8486e..4948aef7 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -210,20 +210,8 @@ struct xtables_args { unsigned long long pcnt_cnt, bcnt_cnt; }; -struct nft_xt_cmd_parse { - unsigned int command; - unsigned int rulenum; - char *table; - const char *chain; - const char *newname; - const char *policy; - bool restore; - int verbose; - bool xlate; -}; - void do_parse(struct nft_handle *h, int argc, char *argv[], - struct nft_xt_cmd_parse *p, struct iptables_command_state *cs, + struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args); struct nftnl_chain_list; diff --git a/iptables/xshared.h b/iptables/xshared.h index 2c05b0d7..dde94b73 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -262,4 +262,16 @@ int print_match_save(const struct xt_entry_match *e, const void *ip); void xtables_printhelp(const struct xtables_rule_match *matches); void exit_tryhelp(int status, int line) __attribute__((noreturn)); +struct xt_cmd_parse { + unsigned int command; + unsigned int rulenum; + char *table; + const char *chain; + const char *newname; + const char *policy; + bool restore; + int verbose; + bool xlate; +}; + #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index a6c86b65..86177024 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -152,7 +152,7 @@ static void print_ebt_cmd(int argc, char *argv[]) printf("\n"); } -static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct nft_xt_cmd_parse *p, +static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse *p, const struct iptables_command_state *cs, bool append) { struct xt_xlate *xl = xt_xlate_alloc(10240); @@ -191,7 +191,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char int selected_chain = -1; struct xtables_rule_match *xtrm_i; struct ebt_match *match; - struct nft_xt_cmd_parse p = { + struct xt_cmd_parse p = { .table = *table, }; diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index e2948c50..9d312b24 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -150,7 +150,7 @@ const char *family2str[] = { }; static int nft_rule_xlate_add(struct nft_handle *h, - const struct nft_xt_cmd_parse *p, + const struct xt_cmd_parse *p, const struct iptables_command_state *cs, bool append) { @@ -186,11 +186,11 @@ err_out: return ret; } -static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p, +static int xlate(struct nft_handle *h, struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args, bool append, int (*cb)(struct nft_handle *h, - const struct nft_xt_cmd_parse *p, + const struct xt_cmd_parse *p, const struct iptables_command_state *cs, bool append)) { @@ -248,7 +248,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], char **table, bool restore) { int ret = 0; - struct nft_xt_cmd_parse p = { + struct xt_cmd_parse p = { .table = *table, .restore = restore, .xlate = true, diff --git a/iptables/xtables.c b/iptables/xtables.c index ac864eb2..837b399a 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -187,7 +187,7 @@ static void check_inverse(struct nft_handle *h, const char option[], } void do_parse(struct nft_handle *h, int argc, char *argv[], - struct nft_xt_cmd_parse *p, struct iptables_command_state *cs, + struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) { struct xtables_match *m; @@ -699,7 +699,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool restore) { int ret = 1; - struct nft_xt_cmd_parse p = { + struct xt_cmd_parse p = { .table = *table, .restore = restore, }; -- cgit v1.2.3 From 17abaeb16afd6cdc17dddb4e1526d31cdfc8cb60 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 23 Dec 2021 18:27:31 +0100 Subject: xtables: Pass xtables_args to check_empty_interface() It holds the accessed family field as well and is more generic than nft_handle. Signed-off-by: Phil Sutter --- iptables/xtables.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iptables/xtables.c b/iptables/xtables.c index 837b399a..db0cec24 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -145,14 +145,14 @@ list_rules(struct nft_handle *h, const char *chain, const char *table, return nft_cmd_rule_list_save(h, chain, table, rulenum, counters); } -static void check_empty_interface(struct nft_handle *h, const char *arg) +static void check_empty_interface(struct xtables_args *args, const char *arg) { const char *msg = "Empty interface is likely to be undesired"; if (*arg != '\0') return; - if (h->family != NFPROTO_ARP) + if (args->family != NFPROTO_ARP) xtables_error(PARAMETER_PROBLEM, msg); fprintf(stderr, "%s", msg); @@ -460,7 +460,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'i': - check_empty_interface(h, optarg); + check_empty_interface(args, optarg); check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEIN, &args->invflags, invert); @@ -470,7 +470,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 'o': - check_empty_interface(h, optarg); + check_empty_interface(args, optarg); check_inverse(h, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEOUT, &args->invflags, invert); -- cgit v1.2.3 From ece001c258e3fd8779e177ef00394877f2327f56 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 23 Dec 2021 18:29:40 +0100 Subject: xtables: Pass xtables_args to check_inverse() It holds the accessed family field as well and is more generic than nft_handle. Signed-off-by: Phil Sutter --- iptables/xtables.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/iptables/xtables.c b/iptables/xtables.c index db0cec24..5e8c027b 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -158,10 +158,10 @@ static void check_empty_interface(struct xtables_args *args, const char *arg) fprintf(stderr, "%s", msg); } -static void check_inverse(struct nft_handle *h, const char option[], +static void check_inverse(struct xtables_args *args, const char option[], bool *invert, int *optidx, int argc) { - switch (h->family) { + switch (args->family) { case NFPROTO_ARP: break; default: @@ -364,7 +364,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], * Option selection */ case 'p': - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_PROTOCOL, &args->invflags, invert); @@ -387,14 +387,14 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], break; case 's': - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_SOURCE, &args->invflags, invert); args->shostnetworkmask = argv[optind - 1]; break; case 'd': - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_DESTINATION, &args->invflags, invert); args->dhostnetworkmask = argv[optind - 1]; @@ -410,21 +410,21 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], #endif case 2:/* src-mac */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_S_MAC, &args->invflags, invert); args->src_mac = argv[optind - 1]; break; case 3:/* dst-mac */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_D_MAC, &args->invflags, invert); args->dst_mac = argv[optind - 1]; break; case 'l':/* hardware length */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_H_LENGTH, &args->invflags, invert); args->arp_hlen = argv[optind - 1]; @@ -433,21 +433,21 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 8: /* was never supported, not even in arptables-legacy */ xtables_error(PARAMETER_PROBLEM, "not supported"); case 4:/* opcode */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_OPCODE, &args->invflags, invert); args->arp_opcode = argv[optind - 1]; break; case 5:/* h-type */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_H_TYPE, &args->invflags, invert); args->arp_htype = argv[optind - 1]; break; case 6:/* proto-type */ - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_P_TYPE, &args->invflags, invert); args->arp_ptype = argv[optind - 1]; @@ -461,7 +461,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'i': check_empty_interface(args, optarg); - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEIN, &args->invflags, invert); xtables_parse_interface(argv[optind - 1], @@ -471,7 +471,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'o': check_empty_interface(args, optarg); - check_inverse(h, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, &optind, argc); set_option(&cs->options, OPT_VIANAMEOUT, &args->invflags, invert); xtables_parse_interface(argv[optind - 1], -- cgit v1.2.3 From 3039a52c3ecf96df4e3b815d242f788c189093e1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 23 Dec 2021 18:55:53 +0100 Subject: xtables: Do not pass nft_handle to do_parse() Make it fit for sharing with legacy iptables, drop nft-specific parameter. This requires to mirror proto_parse and post_parse callbacks from family_ops somewhere reachable - use xt_cmd_parse, it holds other "parser setup data" as well. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 4 +++- iptables/nft-bridge.c | 1 - iptables/nft-ipv4.c | 6 ++++-- iptables/nft-ipv6.c | 6 ++++-- iptables/nft-shared.h | 40 ++-------------------------------------- iptables/xshared.h | 42 ++++++++++++++++++++++++++++++++++++++++++ iptables/xtables-translate.c | 3 ++- iptables/xtables.c | 12 +++++++----- 8 files changed, 64 insertions(+), 50 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b211a309..1472b115 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -802,7 +802,9 @@ struct nft_family_ops nft_family_ops_arp = { .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, - .post_parse = nft_arp_post_parse, + .cmd_parse = { + .post_parse = nft_arp_post_parse, + }, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, .clear_cs = nft_clear_iptables_command_state, diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 5cde302c..90d55e44 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -900,7 +900,6 @@ struct nft_family_ops nft_family_ops_bridge = { .print_rule = nft_bridge_print_rule, .save_rule = nft_bridge_save_rule, .save_chain = nft_bridge_save_chain, - .post_parse = NULL, .rule_to_cs = nft_rule_to_ebtables_command_state, .clear_cs = ebt_cs_clean, .xlate = nft_bridge_xlate, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index f3626098..07da0a7e 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -510,8 +510,10 @@ struct nft_family_ops nft_family_ops_ipv4 = { .print_rule = nft_ipv4_print_rule, .save_rule = nft_ipv4_save_rule, .save_chain = nft_ipv46_save_chain, - .proto_parse = nft_ipv4_proto_parse, - .post_parse = nft_ipv4_post_parse, + .cmd_parse = { + .proto_parse = nft_ipv4_proto_parse, + .post_parse = nft_ipv4_post_parse, + }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = nft_clear_iptables_command_state, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 13213088..4f80ed84 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -495,8 +495,10 @@ struct nft_family_ops nft_family_ops_ipv6 = { .print_rule = nft_ipv6_print_rule, .save_rule = nft_ipv6_save_rule, .save_chain = nft_ipv46_save_chain, - .proto_parse = nft_ipv6_proto_parse, - .post_parse = nft_ipv6_post_parse, + .cmd_parse = { + .proto_parse = nft_ipv6_proto_parse, + .post_parse = nft_ipv6_post_parse, + }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = nft_clear_iptables_command_state, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 4948aef7..195e5fed 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -100,10 +100,7 @@ struct nft_family_ops { unsigned int num, unsigned int format); void (*save_rule)(const void *data, unsigned int format); void (*save_chain)(const struct nftnl_chain *c, const char *policy); - void (*proto_parse)(struct iptables_command_state *cs, - struct xtables_args *args); - void (*post_parse)(int command, struct iptables_command_state *cs, - struct xtables_args *args); + struct xt_cmd_parse_ops cmd_parse; void (*parse_match)(struct xtables_match *m, void *data); void (*parse_target)(struct xtables_target *t, void *data); void (*init_cs)(struct iptables_command_state *cs); @@ -177,40 +174,7 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data); bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); -struct addr_mask { - union { - struct in_addr *v4; - struct in6_addr *v6; - void *ptr; - } addr; - - unsigned int naddrs; - - union { - struct in_addr *v4; - struct in6_addr *v6; - void *ptr; - } mask; -}; - -struct xtables_args { - int family; - uint16_t proto; - uint8_t flags; - uint16_t invflags; - char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; - unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; - bool goto_set; - const char *shostnetworkmask, *dhostnetworkmask; - const char *pcnt, *bcnt; - struct addr_mask s, d; - const char *src_mac, *dst_mac; - const char *arp_hlen, *arp_opcode; - const char *arp_htype, *arp_ptype; - unsigned long long pcnt_cnt, bcnt_cnt; -}; - -void do_parse(struct nft_handle *h, int argc, char *argv[], +void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args); diff --git a/iptables/xshared.h b/iptables/xshared.h index dde94b73..34730be6 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -262,6 +262,47 @@ int print_match_save(const struct xt_entry_match *e, const void *ip); void xtables_printhelp(const struct xtables_rule_match *matches); void exit_tryhelp(int status, int line) __attribute__((noreturn)); +struct addr_mask { + union { + struct in_addr *v4; + struct in6_addr *v6; + void *ptr; + } addr; + + unsigned int naddrs; + + union { + struct in_addr *v4; + struct in6_addr *v6; + void *ptr; + } mask; +}; + +struct xtables_args { + int family; + uint16_t proto; + uint8_t flags; + uint16_t invflags; + char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; + unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; + bool goto_set; + const char *shostnetworkmask, *dhostnetworkmask; + const char *pcnt, *bcnt; + struct addr_mask s, d; + const char *src_mac, *dst_mac; + const char *arp_hlen, *arp_opcode; + const char *arp_htype, *arp_ptype; + unsigned long long pcnt_cnt, bcnt_cnt; +}; + +struct xt_cmd_parse_ops { + void (*proto_parse)(struct iptables_command_state *cs, + struct xtables_args *args); + void (*post_parse)(int command, + struct iptables_command_state *cs, + struct xtables_args *args); +}; + struct xt_cmd_parse { unsigned int command; unsigned int rulenum; @@ -272,6 +313,7 @@ struct xt_cmd_parse { bool restore; int verbose; bool xlate; + struct xt_cmd_parse_ops *ops; }; #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 9d312b24..c287d3bd 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -252,6 +252,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], .table = *table, .restore = restore, .xlate = true, + .ops = &h->ops->cmd_parse, }; struct iptables_command_state cs = { .jumpto = "", @@ -265,7 +266,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], if (h->ops->init_cs) h->ops->init_cs(&cs); - do_parse(h, argc, argv, &p, &cs, &args); + do_parse(argc, argv, &p, &cs, &args); cs.restore = restore; diff --git a/iptables/xtables.c b/iptables/xtables.c index 5e8c027b..59fc63d0 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -186,7 +186,7 @@ static void check_inverse(struct xtables_args *args, const char option[], } } -void do_parse(struct nft_handle *h, int argc, char *argv[], +void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) { @@ -382,8 +382,8 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "rule would never match protocol"); /* This needs to happen here to parse extensions */ - if (h->ops->proto_parse) - h->ops->proto_parse(cs, args); + if (p->ops->proto_parse) + p->ops->proto_parse(cs, args); break; case 's': @@ -653,7 +653,8 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); - h->ops->post_parse(p->command, cs, args); + if (p->ops->post_parse) + p->ops->post_parse(p->command, cs, args); if (p->command == CMD_REPLACE && (args->s.naddrs != 1 || args->d.naddrs != 1)) @@ -702,6 +703,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, struct xt_cmd_parse p = { .table = *table, .restore = restore, + .ops = &h->ops->cmd_parse, }; struct iptables_command_state cs = { .jumpto = "", @@ -714,7 +716,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, if (h->ops->init_cs) h->ops->init_cs(&cs); - do_parse(h, argc, argv, &p, &cs, &args); + do_parse(argc, argv, &p, &cs, &args); if (!nft_table_builtin_find(h, p.table)) xtables_error(VERSION_PROBLEM, -- cgit v1.2.3 From 62c3c93d4b0f5f6b9bb6c6829d507b57b976a644 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 23 Dec 2021 19:03:37 +0100 Subject: xshared: Move do_parse to shared space Small adjustments were needed: - Pass line variable via xt_cmd_parse, xshared.c does not have it in namespace. - Replace opts, prog_name and prog_vers defines by the respective xt_params field reference. Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 4 - iptables/xshared.c | 553 ++++++++++++++++++++++++++++++++++++++++++ iptables/xshared.h | 5 + iptables/xtables-translate.c | 1 + iptables/xtables.c | 556 +------------------------------------------ 5 files changed, 560 insertions(+), 559 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 195e5fed..c3241f4b 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -174,10 +174,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data); bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); -void do_parse(int argc, char *argv[], - struct xt_cmd_parse *p, struct iptables_command_state *cs, - struct xtables_args *args); - struct nftnl_chain_list; struct nft_xt_restore_cb { diff --git a/iptables/xshared.c b/iptables/xshared.c index efee7a30..4c8ee3aa 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1262,3 +1262,556 @@ void exit_tryhelp(int status, int line) xtables_free_opts(1); exit(status); } + +static void check_empty_interface(struct xtables_args *args, const char *arg) +{ + const char *msg = "Empty interface is likely to be undesired"; + + if (*arg != '\0') + return; + + if (args->family != NFPROTO_ARP) + xtables_error(PARAMETER_PROBLEM, msg); + + fprintf(stderr, "%s", msg); +} + +static void check_inverse(struct xtables_args *args, const char option[], + bool *invert, int *optidx, int argc) +{ + switch (args->family) { + case NFPROTO_ARP: + break; + default: + return; + } + + if (!option || strcmp(option, "!")) + return; + + fprintf(stderr, "Using intrapositioned negation (`--option ! this`) " + "is deprecated in favor of extrapositioned (`! --option this`).\n"); + + if (*invert) + xtables_error(PARAMETER_PROBLEM, + "Multiple `!' flags not allowed"); + *invert = true; + if (optidx) { + *optidx = *optidx + 1; + if (argc && *optidx > argc) + xtables_error(PARAMETER_PROBLEM, + "no argument following `!'"); + } +} + +void do_parse(int argc, char *argv[], + struct xt_cmd_parse *p, struct iptables_command_state *cs, + struct xtables_args *args) +{ + struct xtables_match *m; + struct xtables_rule_match *matchp; + bool wait_interval_set = false; + struct timeval wait_interval; + struct xtables_target *t; + bool table_set = false; + bool invert = false; + int wait = 0; + + /* re-set optind to 0 in case do_command4 gets called + * a second time */ + optind = 0; + + /* clear mflags in case do_command4 gets called a second time + * (we clear the global list of all matches for security)*/ + for (m = xtables_matches; m; m = m->next) + m->mflags = 0; + + for (t = xtables_targets; t; t = t->next) { + t->tflags = 0; + t->used = 0; + } + + /* Suppress error messages: we may add new options if we + demand-load a protocol. */ + opterr = 0; + + xt_params->opts = xt_params->orig_opts; + while ((cs->c = getopt_long(argc, argv, xt_params->optstring, + xt_params->opts, NULL)) != -1) { + switch (cs->c) { + /* + * Command selection + */ + case 'A': + add_command(&p->command, CMD_APPEND, CMD_NONE, invert); + p->chain = optarg; + break; + + case 'C': + add_command(&p->command, CMD_CHECK, CMD_NONE, invert); + p->chain = optarg; + break; + + case 'D': + add_command(&p->command, CMD_DELETE, CMD_NONE, invert); + p->chain = optarg; + if (xs_has_arg(argc, argv)) { + p->rulenum = parse_rulenumber(argv[optind++]); + p->command = CMD_DELETE_NUM; + } + break; + + case 'R': + add_command(&p->command, CMD_REPLACE, CMD_NONE, invert); + p->chain = optarg; + if (xs_has_arg(argc, argv)) + p->rulenum = parse_rulenumber(argv[optind++]); + else + xtables_error(PARAMETER_PROBLEM, + "-%c requires a rule number", + cmd2char(CMD_REPLACE)); + break; + + case 'I': + add_command(&p->command, CMD_INSERT, CMD_NONE, invert); + p->chain = optarg; + if (xs_has_arg(argc, argv)) + p->rulenum = parse_rulenumber(argv[optind++]); + else + p->rulenum = 1; + break; + + case 'L': + add_command(&p->command, CMD_LIST, + CMD_ZERO | CMD_ZERO_NUM, invert); + if (optarg) + p->chain = optarg; + else if (xs_has_arg(argc, argv)) + p->chain = argv[optind++]; + if (xs_has_arg(argc, argv)) + p->rulenum = parse_rulenumber(argv[optind++]); + break; + + case 'S': + add_command(&p->command, CMD_LIST_RULES, + CMD_ZERO|CMD_ZERO_NUM, invert); + if (optarg) + p->chain = optarg; + else if (xs_has_arg(argc, argv)) + p->chain = argv[optind++]; + if (xs_has_arg(argc, argv)) + p->rulenum = parse_rulenumber(argv[optind++]); + break; + + case 'F': + add_command(&p->command, CMD_FLUSH, CMD_NONE, invert); + if (optarg) + p->chain = optarg; + else if (xs_has_arg(argc, argv)) + p->chain = argv[optind++]; + break; + + case 'Z': + add_command(&p->command, CMD_ZERO, + CMD_LIST|CMD_LIST_RULES, invert); + if (optarg) + p->chain = optarg; + else if (xs_has_arg(argc, argv)) + p->chain = argv[optind++]; + if (xs_has_arg(argc, argv)) { + p->rulenum = parse_rulenumber(argv[optind++]); + p->command = CMD_ZERO_NUM; + } + break; + + case 'N': + parse_chain(optarg); + add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE, + invert); + p->chain = optarg; + break; + + case 'X': + add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE, + invert); + if (optarg) + p->chain = optarg; + else if (xs_has_arg(argc, argv)) + p->chain = argv[optind++]; + break; + + case 'E': + add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE, + invert); + p->chain = optarg; + if (xs_has_arg(argc, argv)) + p->newname = argv[optind++]; + else + xtables_error(PARAMETER_PROBLEM, + "-%c requires old-chain-name and " + "new-chain-name", + cmd2char(CMD_RENAME_CHAIN)); + break; + + case 'P': + add_command(&p->command, CMD_SET_POLICY, CMD_NONE, + invert); + p->chain = optarg; + if (xs_has_arg(argc, argv)) + p->policy = argv[optind++]; + else + xtables_error(PARAMETER_PROBLEM, + "-%c requires a chain and a policy", + cmd2char(CMD_SET_POLICY)); + break; + + case 'h': + if (!optarg) + optarg = argv[optind]; + + /* iptables -p icmp -h */ + if (!cs->matches && cs->protocol) + xtables_find_match(cs->protocol, + XTF_TRY_LOAD, &cs->matches); + + xt_params->print_help(cs->matches); + p->command = CMD_NONE; + return; + + /* + * Option selection + */ + case 'p': + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_PROTOCOL, + &args->invflags, invert); + + /* Canonicalize into lower case */ + for (cs->protocol = argv[optind - 1]; + *cs->protocol; cs->protocol++) + *cs->protocol = tolower(*cs->protocol); + + cs->protocol = argv[optind - 1]; + args->proto = xtables_parse_protocol(cs->protocol); + + if (args->proto == 0 && + (args->invflags & XT_INV_PROTO)) + xtables_error(PARAMETER_PROBLEM, + "rule would never match protocol"); + + /* This needs to happen here to parse extensions */ + if (p->ops->proto_parse) + p->ops->proto_parse(cs, args); + break; + + case 's': + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_SOURCE, + &args->invflags, invert); + args->shostnetworkmask = argv[optind - 1]; + break; + + case 'd': + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_DESTINATION, + &args->invflags, invert); + args->dhostnetworkmask = argv[optind - 1]; + break; + +#ifdef IPT_F_GOTO + case 'g': + set_option(&cs->options, OPT_JUMP, &args->invflags, + invert); + args->goto_set = true; + cs->jumpto = xt_parse_target(optarg); + break; +#endif + + case 2:/* src-mac */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_S_MAC, &args->invflags, + invert); + args->src_mac = argv[optind - 1]; + break; + + case 3:/* dst-mac */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_D_MAC, &args->invflags, + invert); + args->dst_mac = argv[optind - 1]; + break; + + case 'l':/* hardware length */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_H_LENGTH, &args->invflags, + invert); + args->arp_hlen = argv[optind - 1]; + break; + + case 8: /* was never supported, not even in arptables-legacy */ + xtables_error(PARAMETER_PROBLEM, "not supported"); + case 4:/* opcode */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_OPCODE, &args->invflags, + invert); + args->arp_opcode = argv[optind - 1]; + break; + + case 5:/* h-type */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_H_TYPE, &args->invflags, + invert); + args->arp_htype = argv[optind - 1]; + break; + + case 6:/* proto-type */ + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_P_TYPE, &args->invflags, + invert); + args->arp_ptype = argv[optind - 1]; + break; + + case 'j': + set_option(&cs->options, OPT_JUMP, &args->invflags, + invert); + command_jump(cs, argv[optind - 1]); + break; + + case 'i': + check_empty_interface(args, optarg); + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_VIANAMEIN, + &args->invflags, invert); + xtables_parse_interface(argv[optind - 1], + args->iniface, + args->iniface_mask); + break; + + case 'o': + check_empty_interface(args, optarg); + check_inverse(args, optarg, &invert, &optind, argc); + set_option(&cs->options, OPT_VIANAMEOUT, + &args->invflags, invert); + xtables_parse_interface(argv[optind - 1], + args->outiface, + args->outiface_mask); + break; + + case 'f': + if (args->family == AF_INET6) { + xtables_error(PARAMETER_PROBLEM, + "`-f' is not supported in IPv6, " + "use -m frag instead"); + } + set_option(&cs->options, OPT_FRAGMENT, &args->invflags, + invert); + args->flags |= IPT_F_FRAG; + break; + + case 'v': + if (!p->verbose) + set_option(&cs->options, OPT_VERBOSE, + &args->invflags, invert); + p->verbose++; + break; + + case 'm': + command_match(cs, invert); + break; + + case 'n': + set_option(&cs->options, OPT_NUMERIC, &args->invflags, + invert); + break; + + case 't': + if (invert) + xtables_error(PARAMETER_PROBLEM, + "unexpected ! flag before --table"); + if (p->restore && table_set) + xtables_error(PARAMETER_PROBLEM, + "The -t option cannot be used in %s.\n", + xt_params->program_name); + p->table = optarg; + table_set = true; + break; + + case 'x': + set_option(&cs->options, OPT_EXPANDED, &args->invflags, + invert); + break; + + case 'V': + if (invert) + printf("Not %s ;-)\n", + xt_params->program_version); + else + printf("%s v%s\n", + xt_params->program_name, + xt_params->program_version); + exit(0); + + case 'w': + if (p->restore) { + xtables_error(PARAMETER_PROBLEM, + "You cannot use `-w' from " + "iptables-restore"); + } + + wait = parse_wait_time(argc, argv); + break; + + case 'W': + if (p->restore) { + xtables_error(PARAMETER_PROBLEM, + "You cannot use `-W' from " + "iptables-restore"); + } + + parse_wait_interval(argc, argv, &wait_interval); + wait_interval_set = true; + break; + + case '0': + set_option(&cs->options, OPT_LINENUMBERS, + &args->invflags, invert); + break; + + case 'M': + xtables_modprobe_program = optarg; + break; + + case 'c': + set_option(&cs->options, OPT_COUNTERS, &args->invflags, + invert); + args->pcnt = optarg; + args->bcnt = strchr(args->pcnt + 1, ','); + if (args->bcnt) + args->bcnt++; + if (!args->bcnt && xs_has_arg(argc, argv)) + args->bcnt = argv[optind++]; + if (!args->bcnt) + xtables_error(PARAMETER_PROBLEM, + "-%c requires packet and byte counter", + opt2char(OPT_COUNTERS)); + + if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1) + xtables_error(PARAMETER_PROBLEM, + "-%c packet counter not numeric", + opt2char(OPT_COUNTERS)); + + if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1) + xtables_error(PARAMETER_PROBLEM, + "-%c byte counter not numeric", + opt2char(OPT_COUNTERS)); + break; + + case '4': + if (args->family == AF_INET) + break; + + if (p->restore && args->family == AF_INET6) + return; + + exit_tryhelp(2, p->line); + + case '6': + if (args->family == AF_INET6) + break; + + if (p->restore && args->family == AF_INET) + return; + + exit_tryhelp(2, p->line); + + case 1: /* non option */ + if (optarg[0] == '!' && optarg[1] == '\0') { + if (invert) + xtables_error(PARAMETER_PROBLEM, + "multiple consecutive ! not" + " allowed"); + invert = true; + optarg[0] = '\0'; + continue; + } + fprintf(stderr, "Bad argument `%s'\n", optarg); + exit_tryhelp(2, p->line); + + default: + if (command_default(cs, xt_params, invert)) + /* cf. ip6tables.c */ + continue; + break; + } + invert = false; + } + + if (strcmp(p->table, "nat") == 0 && + ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) || + (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0))) + xtables_error(PARAMETER_PROBLEM, + "\nThe \"nat\" table is not intended for filtering, " + "the use of DROP is therefore inhibited.\n\n"); + + if (!wait && wait_interval_set) + xtables_error(PARAMETER_PROBLEM, + "--wait-interval only makes sense with --wait\n"); + + for (matchp = cs->matches; matchp; matchp = matchp->next) + xtables_option_mfcall(matchp->match); + if (cs->target != NULL) + xtables_option_tfcall(cs->target); + + /* Fix me: must put inverse options checking here --MN */ + + if (optind < argc) + xtables_error(PARAMETER_PROBLEM, + "unknown arguments found on commandline"); + if (!p->command) + xtables_error(PARAMETER_PROBLEM, "no command specified"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "nothing appropriate following !"); + + if (p->ops->post_parse) + p->ops->post_parse(p->command, cs, args); + + if (p->command == CMD_REPLACE && + (args->s.naddrs != 1 || args->d.naddrs != 1)) + xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " + "specify a unique address"); + + generic_opt_check(p->command, cs->options); + + if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, + "chain name `%s' too long (must be under %u chars)", + p->chain, XT_EXTENSION_MAXNAMELEN); + + if (p->command == CMD_APPEND || + p->command == CMD_DELETE || + p->command == CMD_DELETE_NUM || + p->command == CMD_CHECK || + p->command == CMD_INSERT || + p->command == CMD_REPLACE) { + if (strcmp(p->chain, "PREROUTING") == 0 + || strcmp(p->chain, "INPUT") == 0) { + /* -o not valid with incoming packets. */ + if (cs->options & OPT_VIANAMEOUT) + xtables_error(PARAMETER_PROBLEM, + "Can't use -%c with %s\n", + opt2char(OPT_VIANAMEOUT), + p->chain); + } + + if (strcmp(p->chain, "POSTROUTING") == 0 + || strcmp(p->chain, "OUTPUT") == 0) { + /* -i not valid with outgoing packets */ + if (cs->options & OPT_VIANAMEIN) + xtables_error(PARAMETER_PROBLEM, + "Can't use -%c with %s\n", + opt2char(OPT_VIANAMEIN), + p->chain); + } + } +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 34730be6..13ea05fe 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -311,9 +311,14 @@ struct xt_cmd_parse { const char *newname; const char *policy; bool restore; + int line; int verbose; bool xlate; struct xt_cmd_parse_ops *ops; }; +void do_parse(int argc, char *argv[], + struct xt_cmd_parse *p, struct iptables_command_state *cs, + struct xtables_args *args); + #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index c287d3bd..6a1cdac1 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -251,6 +251,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], struct xt_cmd_parse p = { .table = *table, .restore = restore, + .line = line, .xlate = true, .ops = &h->ops->cmd_parse, }; diff --git a/iptables/xtables.c b/iptables/xtables.c index 59fc63d0..051d5c7b 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -95,10 +95,6 @@ struct xtables_globals xtables_globals = { .print_help = xtables_printhelp, }; -#define opts xt_params->opts -#define prog_name xt_params->program_name -#define prog_vers xt_params->program_version - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -145,557 +141,6 @@ list_rules(struct nft_handle *h, const char *chain, const char *table, return nft_cmd_rule_list_save(h, chain, table, rulenum, counters); } -static void check_empty_interface(struct xtables_args *args, const char *arg) -{ - const char *msg = "Empty interface is likely to be undesired"; - - if (*arg != '\0') - return; - - if (args->family != NFPROTO_ARP) - xtables_error(PARAMETER_PROBLEM, msg); - - fprintf(stderr, "%s", msg); -} - -static void check_inverse(struct xtables_args *args, const char option[], - bool *invert, int *optidx, int argc) -{ - switch (args->family) { - case NFPROTO_ARP: - break; - default: - return; - } - - if (!option || strcmp(option, "!")) - return; - - fprintf(stderr, "Using intrapositioned negation (`--option ! this`) " - "is deprecated in favor of extrapositioned (`! --option this`).\n"); - - if (*invert) - xtables_error(PARAMETER_PROBLEM, - "Multiple `!' flags not allowed"); - *invert = true; - if (optidx) { - *optidx = *optidx + 1; - if (argc && *optidx > argc) - xtables_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } -} - -void do_parse(int argc, char *argv[], - struct xt_cmd_parse *p, struct iptables_command_state *cs, - struct xtables_args *args) -{ - struct xtables_match *m; - struct xtables_rule_match *matchp; - bool wait_interval_set = false; - struct timeval wait_interval; - struct xtables_target *t; - bool table_set = false; - bool invert = false; - int wait = 0; - - /* re-set optind to 0 in case do_command4 gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command4 gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = xtables_matches; m; m = m->next) - m->mflags = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - - opts = xt_params->orig_opts; - while ((cs->c = getopt_long(argc, argv, xt_params->optstring, - opts, NULL)) != -1) { - switch (cs->c) { - /* - * Command selection - */ - case 'A': - add_command(&p->command, CMD_APPEND, CMD_NONE, invert); - p->chain = optarg; - break; - - case 'C': - add_command(&p->command, CMD_CHECK, CMD_NONE, invert); - p->chain = optarg; - break; - - case 'D': - add_command(&p->command, CMD_DELETE, CMD_NONE, invert); - p->chain = optarg; - if (xs_has_arg(argc, argv)) { - p->rulenum = parse_rulenumber(argv[optind++]); - p->command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&p->command, CMD_REPLACE, CMD_NONE, invert); - p->chain = optarg; - if (xs_has_arg(argc, argv)) - p->rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&p->command, CMD_INSERT, CMD_NONE, invert); - p->chain = optarg; - if (xs_has_arg(argc, argv)) - p->rulenum = parse_rulenumber(argv[optind++]); - else - p->rulenum = 1; - break; - - case 'L': - add_command(&p->command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) - p->chain = optarg; - else if (xs_has_arg(argc, argv)) - p->chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - p->rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'S': - add_command(&p->command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, invert); - if (optarg) - p->chain = optarg; - else if (xs_has_arg(argc, argv)) - p->chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - p->rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'F': - add_command(&p->command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) - p->chain = optarg; - else if (xs_has_arg(argc, argv)) - p->chain = argv[optind++]; - break; - - case 'Z': - add_command(&p->command, CMD_ZERO, - CMD_LIST|CMD_LIST_RULES, invert); - if (optarg) - p->chain = optarg; - else if (xs_has_arg(argc, argv)) - p->chain = argv[optind++]; - if (xs_has_arg(argc, argv)) { - p->rulenum = parse_rulenumber(argv[optind++]); - p->command = CMD_ZERO_NUM; - } - break; - - case 'N': - parse_chain(optarg); - add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE, - invert); - p->chain = optarg; - break; - - case 'X': - add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) - p->chain = optarg; - else if (xs_has_arg(argc, argv)) - p->chain = argv[optind++]; - break; - - case 'E': - add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - p->chain = optarg; - if (xs_has_arg(argc, argv)) - p->newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&p->command, CMD_SET_POLICY, CMD_NONE, - invert); - p->chain = optarg; - if (xs_has_arg(argc, argv)) - p->policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!cs->matches && cs->protocol) - xtables_find_match(cs->protocol, - XTF_TRY_LOAD, &cs->matches); - - xt_params->print_help(cs->matches); - p->command = CMD_NONE; - return; - - /* - * Option selection - */ - case 'p': - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_PROTOCOL, - &args->invflags, invert); - - /* Canonicalize into lower case */ - for (cs->protocol = argv[optind - 1]; - *cs->protocol; cs->protocol++) - *cs->protocol = tolower(*cs->protocol); - - cs->protocol = argv[optind - 1]; - args->proto = xtables_parse_protocol(cs->protocol); - - if (args->proto == 0 && - (args->invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - - /* This needs to happen here to parse extensions */ - if (p->ops->proto_parse) - p->ops->proto_parse(cs, args); - break; - - case 's': - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_SOURCE, - &args->invflags, invert); - args->shostnetworkmask = argv[optind - 1]; - break; - - case 'd': - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_DESTINATION, - &args->invflags, invert); - args->dhostnetworkmask = argv[optind - 1]; - break; - -#ifdef IPT_F_GOTO - case 'g': - set_option(&cs->options, OPT_JUMP, &args->invflags, - invert); - args->goto_set = true; - cs->jumpto = xt_parse_target(optarg); - break; -#endif - - case 2:/* src-mac */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_S_MAC, &args->invflags, - invert); - args->src_mac = argv[optind - 1]; - break; - - case 3:/* dst-mac */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_D_MAC, &args->invflags, - invert); - args->dst_mac = argv[optind - 1]; - break; - - case 'l':/* hardware length */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_H_LENGTH, &args->invflags, - invert); - args->arp_hlen = argv[optind - 1]; - break; - - case 8: /* was never supported, not even in arptables-legacy */ - xtables_error(PARAMETER_PROBLEM, "not supported"); - case 4:/* opcode */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_OPCODE, &args->invflags, - invert); - args->arp_opcode = argv[optind - 1]; - break; - - case 5:/* h-type */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_H_TYPE, &args->invflags, - invert); - args->arp_htype = argv[optind - 1]; - break; - - case 6:/* proto-type */ - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_P_TYPE, &args->invflags, - invert); - args->arp_ptype = argv[optind - 1]; - break; - - case 'j': - set_option(&cs->options, OPT_JUMP, &args->invflags, - invert); - command_jump(cs, argv[optind - 1]); - break; - - case 'i': - check_empty_interface(args, optarg); - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_VIANAMEIN, - &args->invflags, invert); - xtables_parse_interface(argv[optind - 1], - args->iniface, - args->iniface_mask); - break; - - case 'o': - check_empty_interface(args, optarg); - check_inverse(args, optarg, &invert, &optind, argc); - set_option(&cs->options, OPT_VIANAMEOUT, - &args->invflags, invert); - xtables_parse_interface(argv[optind - 1], - args->outiface, - args->outiface_mask); - break; - - case 'f': - if (args->family == AF_INET6) { - xtables_error(PARAMETER_PROBLEM, - "`-f' is not supported in IPv6, " - "use -m frag instead"); - } - set_option(&cs->options, OPT_FRAGMENT, &args->invflags, - invert); - args->flags |= IPT_F_FRAG; - break; - - case 'v': - if (!p->verbose) - set_option(&cs->options, OPT_VERBOSE, - &args->invflags, invert); - p->verbose++; - break; - - case 'm': - command_match(cs, invert); - break; - - case 'n': - set_option(&cs->options, OPT_NUMERIC, &args->invflags, - invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - if (p->restore && table_set) - xtables_error(PARAMETER_PROBLEM, - "The -t option cannot be used in %s.\n", - xt_params->program_name); - p->table = optarg; - table_set = true; - break; - - case 'x': - set_option(&cs->options, OPT_EXPANDED, &args->invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", prog_vers); - else - printf("%s v%s\n", - prog_name, prog_vers); - exit(0); - - case 'w': - if (p->restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-w' from " - "iptables-restore"); - } - - wait = parse_wait_time(argc, argv); - break; - - case 'W': - if (p->restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-W' from " - "iptables-restore"); - } - - parse_wait_interval(argc, argv, &wait_interval); - wait_interval_set = true; - break; - - case '0': - set_option(&cs->options, OPT_LINENUMBERS, - &args->invflags, invert); - break; - - case 'M': - xtables_modprobe_program = optarg; - break; - - case 'c': - set_option(&cs->options, OPT_COUNTERS, &args->invflags, - invert); - args->pcnt = optarg; - args->bcnt = strchr(args->pcnt + 1, ','); - if (args->bcnt) - args->bcnt++; - if (!args->bcnt && xs_has_arg(argc, argv)) - args->bcnt = argv[optind++]; - if (!args->bcnt) - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - break; - - case '4': - if (args->family == AF_INET) - break; - - if (p->restore && args->family == AF_INET6) - return; - - exit_tryhelp(2, line); - - case '6': - if (args->family == AF_INET6) - break; - - if (p->restore && args->family == AF_INET) - return; - - exit_tryhelp(2, line); - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2, line); - - default: - if (command_default(cs, xt_params, invert)) - /* cf. ip6tables.c */ - continue; - break; - } - invert = false; - } - - if (strcmp(p->table, "nat") == 0 && - ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) || - (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0))) - xtables_error(PARAMETER_PROBLEM, - "\nThe \"nat\" table is not intended for filtering, " - "the use of DROP is therefore inhibited.\n\n"); - - if (!wait && wait_interval_set) - xtables_error(PARAMETER_PROBLEM, - "--wait-interval only makes sense with --wait\n"); - - for (matchp = cs->matches; matchp; matchp = matchp->next) - xtables_option_mfcall(matchp->match); - if (cs->target != NULL) - xtables_option_tfcall(cs->target); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!p->command) - xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - if (p->ops->post_parse) - p->ops->post_parse(p->command, cs, args); - - if (p->command == CMD_REPLACE && - (args->s.naddrs != 1 || args->d.naddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - generic_opt_check(p->command, cs->options); - - if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %u chars)", - p->chain, XT_EXTENSION_MAXNAMELEN); - - if (p->command == CMD_APPEND || - p->command == CMD_DELETE || - p->command == CMD_DELETE_NUM || - p->command == CMD_CHECK || - p->command == CMD_INSERT || - p->command == CMD_REPLACE) { - if (strcmp(p->chain, "PREROUTING") == 0 - || strcmp(p->chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs->options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - p->chain); - } - - if (strcmp(p->chain, "POSTROUTING") == 0 - || strcmp(p->chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs->options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - p->chain); - } - } -} - int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool restore) { @@ -703,6 +148,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, struct xt_cmd_parse p = { .table = *table, .restore = restore, + .line = line, .ops = &h->ops->cmd_parse, }; struct iptables_command_state cs = { -- cgit v1.2.3 From ded7b57977f3fa619975f752a342046225b56935 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 24 Dec 2021 14:17:50 +0100 Subject: xshared: Store parsed wait and wait_interval in xtables_args While nft-variants don't care, legacy ones do. Signed-off-by: Phil Sutter --- iptables/xshared.c | 8 +++----- iptables/xshared.h | 2 ++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 4c8ee3aa..b7dad707 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1311,11 +1311,9 @@ void do_parse(int argc, char *argv[], struct xtables_match *m; struct xtables_rule_match *matchp; bool wait_interval_set = false; - struct timeval wait_interval; struct xtables_target *t; bool table_set = false; bool invert = false; - int wait = 0; /* re-set optind to 0 in case do_command4 gets called * a second time */ @@ -1658,7 +1656,7 @@ void do_parse(int argc, char *argv[], "iptables-restore"); } - wait = parse_wait_time(argc, argv); + args->wait = parse_wait_time(argc, argv); break; case 'W': @@ -1668,7 +1666,7 @@ void do_parse(int argc, char *argv[], "iptables-restore"); } - parse_wait_interval(argc, argv, &wait_interval); + parse_wait_interval(argc, argv, &args->wait_interval); wait_interval_set = true; break; @@ -1753,7 +1751,7 @@ void do_parse(int argc, char *argv[], "\nThe \"nat\" table is not intended for filtering, " "the use of DROP is therefore inhibited.\n\n"); - if (!wait && wait_interval_set) + if (!args->wait && wait_interval_set) xtables_error(PARAMETER_PROBLEM, "--wait-interval only makes sense with --wait\n"); diff --git a/iptables/xshared.h b/iptables/xshared.h index 13ea05fe..48bfe911 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -293,6 +293,8 @@ struct xtables_args { const char *arp_hlen, *arp_opcode; const char *arp_htype, *arp_ptype; unsigned long long pcnt_cnt, bcnt_cnt; + int wait; + struct timeval wait_interval; }; struct xt_cmd_parse_ops { -- cgit v1.2.3 From e4f5185d8f29a8d5b62159cb361648acd55da2a6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 24 Dec 2021 14:55:28 +0100 Subject: nft: Move proto_parse and post_parse callbacks to xshared They are not nft-variant-specific and may therefore be shared with legacy. Signed-off-by: Phil Sutter --- iptables/nft-ipv4.c | 59 +----------------------- iptables/nft-ipv6.c | 76 +------------------------------ iptables/xshared.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++ iptables/xshared.h | 9 ++++ 4 files changed, 139 insertions(+), 131 deletions(-) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 07da0a7e..f374d468 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -274,61 +274,6 @@ static void nft_ipv4_save_rule(const void *data, unsigned int format) &cs->fw, format); } -static void nft_ipv4_proto_parse(struct iptables_command_state *cs, - struct xtables_args *args) -{ - cs->fw.ip.proto = args->proto; - cs->fw.ip.invflags = args->invflags; -} - -static void nft_ipv4_post_parse(int command, - struct iptables_command_state *cs, - struct xtables_args *args) -{ - cs->fw.ip.flags = args->flags; - /* We already set invflags in proto_parse, but we need to refresh it - * to include new parsed options. - */ - cs->fw.ip.invflags = args->invflags; - - memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ); - memcpy(cs->fw.ip.iniface_mask, - args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); - - memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ); - memcpy(cs->fw.ip.outiface_mask, - args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); - - if (args->goto_set) - cs->fw.ip.flags |= IPT_F_GOTO; - - cs->counters.pcnt = args->pcnt_cnt; - cs->counters.bcnt = args->bcnt_cnt; - - if (command & (CMD_REPLACE | CMD_INSERT | - CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs->options & OPT_DESTINATION)) - args->dhostnetworkmask = "0.0.0.0/0"; - if (!(cs->options & OPT_SOURCE)) - args->shostnetworkmask = "0.0.0.0/0"; - } - - if (args->shostnetworkmask) - xtables_ipparse_multiple(args->shostnetworkmask, - &args->s.addr.v4, &args->s.mask.v4, - &args->s.naddrs); - if (args->dhostnetworkmask) - xtables_ipparse_multiple(args->dhostnetworkmask, - &args->d.addr.v4, &args->d.mask.v4, - &args->d.naddrs); - - if ((args->s.naddrs > 1 || args->d.naddrs > 1) && - (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, - "! not allowed with multiple" - " source or destination IP addresses"); -} - static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr, const struct in_addr *mask, bool inv, struct xt_xlate *xl) @@ -511,8 +456,8 @@ struct nft_family_ops nft_family_ops_ipv4 = { .save_rule = nft_ipv4_save_rule, .save_chain = nft_ipv46_save_chain, .cmd_parse = { - .proto_parse = nft_ipv4_proto_parse, - .post_parse = nft_ipv4_post_parse, + .proto_parse = ipv4_proto_parse, + .post_parse = ipv4_post_parse, }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 4f80ed84..9ecc754f 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -236,78 +236,6 @@ static void nft_ipv6_save_rule(const void *data, unsigned int format) &cs->fw6, format); } -/* These are invalid numbers as upper layer protocol */ -static int is_exthdr(uint16_t proto) -{ - return (proto == IPPROTO_ROUTING || - proto == IPPROTO_FRAGMENT || - proto == IPPROTO_AH || - proto == IPPROTO_DSTOPTS); -} - -static void nft_ipv6_proto_parse(struct iptables_command_state *cs, - struct xtables_args *args) -{ - cs->fw6.ipv6.proto = args->proto; - cs->fw6.ipv6.invflags = args->invflags; - - if (is_exthdr(cs->fw6.ipv6.proto) - && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0) - fprintf(stderr, - "Warning: never matched protocol: %s. " - "use extension match instead.\n", - cs->protocol); -} - -static void nft_ipv6_post_parse(int command, struct iptables_command_state *cs, - struct xtables_args *args) -{ - cs->fw6.ipv6.flags = args->flags; - /* We already set invflags in proto_parse, but we need to refresh it - * to include new parsed options. - */ - cs->fw6.ipv6.invflags = args->invflags; - - memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ); - memcpy(cs->fw6.ipv6.iniface_mask, - args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); - - memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ); - memcpy(cs->fw6.ipv6.outiface_mask, - args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); - - if (args->goto_set) - cs->fw6.ipv6.flags |= IP6T_F_GOTO; - - cs->fw6.counters.pcnt = args->pcnt_cnt; - cs->fw6.counters.bcnt = args->bcnt_cnt; - - if (command & (CMD_REPLACE | CMD_INSERT | - CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs->options & OPT_DESTINATION)) - args->dhostnetworkmask = "::0/0"; - if (!(cs->options & OPT_SOURCE)) - args->shostnetworkmask = "::0/0"; - } - - if (args->shostnetworkmask) - xtables_ip6parse_multiple(args->shostnetworkmask, - &args->s.addr.v6, - &args->s.mask.v6, - &args->s.naddrs); - if (args->dhostnetworkmask) - xtables_ip6parse_multiple(args->dhostnetworkmask, - &args->d.addr.v6, - &args->d.mask.v6, - &args->d.naddrs); - - if ((args->s.naddrs > 1 || args->d.naddrs > 1) && - (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, - "! not allowed with multiple" - " source or destination IP addresses"); -} - static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr, const struct in6_addr *mask, int invert, struct xt_xlate *xl) @@ -496,8 +424,8 @@ struct nft_family_ops nft_family_ops_ipv6 = { .save_rule = nft_ipv6_save_rule, .save_chain = nft_ipv46_save_chain, .cmd_parse = { - .proto_parse = nft_ipv6_proto_parse, - .post_parse = nft_ipv6_post_parse, + .proto_parse = ipv6_proto_parse, + .post_parse = ipv6_post_parse, }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, diff --git a/iptables/xshared.c b/iptables/xshared.c index b7dad707..a3985d45 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1813,3 +1813,129 @@ void do_parse(int argc, char *argv[], } } } + +void ipv4_proto_parse(struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->fw.ip.proto = args->proto; + cs->fw.ip.invflags = args->invflags; +} + +/* These are invalid numbers as upper layer protocol */ +static int is_exthdr(uint16_t proto) +{ + return (proto == IPPROTO_ROUTING || + proto == IPPROTO_FRAGMENT || + proto == IPPROTO_AH || + proto == IPPROTO_DSTOPTS); +} + +void ipv6_proto_parse(struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->fw6.ipv6.proto = args->proto; + cs->fw6.ipv6.invflags = args->invflags; + + if (is_exthdr(cs->fw6.ipv6.proto) + && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0) + fprintf(stderr, + "Warning: never matched protocol: %s. " + "use extension match instead.\n", + cs->protocol); +} + +void ipv4_post_parse(int command, struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->fw.ip.flags = args->flags; + /* We already set invflags in proto_parse, but we need to refresh it + * to include new parsed options. + */ + cs->fw.ip.invflags = args->invflags; + + memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->fw.ip.iniface_mask, + args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); + + memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->fw.ip.outiface_mask, + args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); + + if (args->goto_set) + cs->fw.ip.flags |= IPT_F_GOTO; + + cs->counters.pcnt = args->pcnt_cnt; + cs->counters.bcnt = args->bcnt_cnt; + + if (command & (CMD_REPLACE | CMD_INSERT | + CMD_DELETE | CMD_APPEND | CMD_CHECK)) { + if (!(cs->options & OPT_DESTINATION)) + args->dhostnetworkmask = "0.0.0.0/0"; + if (!(cs->options & OPT_SOURCE)) + args->shostnetworkmask = "0.0.0.0/0"; + } + + if (args->shostnetworkmask) + xtables_ipparse_multiple(args->shostnetworkmask, + &args->s.addr.v4, &args->s.mask.v4, + &args->s.naddrs); + if (args->dhostnetworkmask) + xtables_ipparse_multiple(args->dhostnetworkmask, + &args->d.addr.v4, &args->d.mask.v4, + &args->d.naddrs); + + if ((args->s.naddrs > 1 || args->d.naddrs > 1) && + (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) + xtables_error(PARAMETER_PROBLEM, + "! not allowed with multiple" + " source or destination IP addresses"); +} + +void ipv6_post_parse(int command, struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->fw6.ipv6.flags = args->flags; + /* We already set invflags in proto_parse, but we need to refresh it + * to include new parsed options. + */ + cs->fw6.ipv6.invflags = args->invflags; + + memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->fw6.ipv6.iniface_mask, + args->iniface_mask, IFNAMSIZ*sizeof(unsigned char)); + + memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->fw6.ipv6.outiface_mask, + args->outiface_mask, IFNAMSIZ*sizeof(unsigned char)); + + if (args->goto_set) + cs->fw6.ipv6.flags |= IP6T_F_GOTO; + + cs->fw6.counters.pcnt = args->pcnt_cnt; + cs->fw6.counters.bcnt = args->bcnt_cnt; + + if (command & (CMD_REPLACE | CMD_INSERT | + CMD_DELETE | CMD_APPEND | CMD_CHECK)) { + if (!(cs->options & OPT_DESTINATION)) + args->dhostnetworkmask = "::0/0"; + if (!(cs->options & OPT_SOURCE)) + args->shostnetworkmask = "::0/0"; + } + + if (args->shostnetworkmask) + xtables_ip6parse_multiple(args->shostnetworkmask, + &args->s.addr.v6, + &args->s.mask.v6, + &args->s.naddrs); + if (args->dhostnetworkmask) + xtables_ip6parse_multiple(args->dhostnetworkmask, + &args->d.addr.v6, + &args->d.mask.v6, + &args->d.naddrs); + + if ((args->s.naddrs > 1 || args->d.naddrs > 1) && + (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) + xtables_error(PARAMETER_PROBLEM, + "! not allowed with multiple" + " source or destination IP addresses"); +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 48bfe911..d13de95e 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -323,4 +323,13 @@ void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args); +void ipv4_proto_parse(struct iptables_command_state *cs, + struct xtables_args *args); +void ipv6_proto_parse(struct iptables_command_state *cs, + struct xtables_args *args); +void ipv4_post_parse(int command, struct iptables_command_state *cs, + struct xtables_args *args); +void ipv6_post_parse(int command, struct iptables_command_state *cs, + struct xtables_args *args); + #endif /* IPTABLES_XSHARED_H */ -- cgit v1.2.3 From 9baf3bf0e77dab6ca4b167554ec0e57b65d0af01 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 4 Nov 2021 15:42:16 +0100 Subject: iptables: Use xtables' do_parse() function To do so, a few conversions are needed: - Make use of xt_params->optstring - Make use of xt_params->print_help callback - Switch to using a proto_parse callback Signed-off-by: Phil Sutter --- iptables/iptables.c | 487 ++++------------------------------------------------ iptables/xshared.c | 3 + 2 files changed, 39 insertions(+), 451 deletions(-) diff --git a/iptables/iptables.c b/iptables/iptables.c index 7dc4cbc1..f5fe868c 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -87,21 +87,12 @@ static struct option original_opts[] = { struct xtables_globals iptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", + .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, + .print_help = xtables_printhelp, }; -#define opts iptables_globals.opts -#define prog_name iptables_globals.program_name -#define prog_vers iptables_globals.program_version - -static void -exit_printhelp(const struct xtables_rule_match *matches) -{ - xtables_printhelp(matches); - exit(0); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -699,10 +690,24 @@ generate_entry(const struct ipt_entry *fw, int do_command4(int argc, char *argv[], char **table, struct xtc_handle **handle, bool restore) { + struct xt_cmd_parse_ops cmd_parse_ops = { + .proto_parse = ipv4_proto_parse, + .post_parse = ipv4_post_parse, + }; + struct xt_cmd_parse p = { + .table = *table, + .restore = restore, + .line = line, + .ops = &cmd_parse_ops, + }; struct iptables_command_state cs = { .jumpto = "", .argv = argv, }; + struct xtables_args args = { + .family = AF_INET, + .wait_interval.tv_sec = 1, + }; struct ipt_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *smasks = NULL; @@ -710,433 +715,30 @@ int do_command4(int argc, char *argv[], char **table, struct timeval wait_interval = { .tv_sec = 1, }; - bool wait_interval_set = false; int verbose = 0; int wait = 0; const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct xtables_match *m; - struct xtables_rule_match *matchp; - struct xtables_target *t; - unsigned long long cnt; - bool table_set = false; - uint16_t invflags = 0; - bool invert = false; - - /* re-set optind to 0 in case do_command4 gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command4 gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = xtables_matches; m; m = m->next) - m->mflags = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - opts = xt_params->orig_opts; - while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46", - opts, NULL)) != -1) { - switch (cs.c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, invert); - chain = optarg; - break; - - case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'S': - add_command(&command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_ZERO_NUM; - } - break; - - case 'N': - parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!cs.matches && cs.protocol) - xtables_find_match(cs.protocol, - XTF_TRY_LOAD, &cs.matches); - - exit_printhelp(cs.matches); - - /* - * Option selection - */ - case 'p': - set_option(&cs.options, OPT_PROTOCOL, &invflags, - invert); - - /* Canonicalize into lower case */ - for (cs.protocol = optarg; *cs.protocol; cs.protocol++) - *cs.protocol = tolower(*cs.protocol); - - cs.protocol = optarg; - cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); - - if (cs.fw.ip.proto == 0 && (invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - break; - - case 's': - set_option(&cs.options, OPT_SOURCE, &invflags, invert); - shostnetworkmask = optarg; - break; - - case 'd': - set_option(&cs.options, OPT_DESTINATION, &invflags, - invert); - dhostnetworkmask = optarg; - break; - -#ifdef IPT_F_GOTO - case 'g': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - cs.fw.ip.flags |= IPT_F_GOTO; - cs.jumpto = xt_parse_target(optarg); - break; -#endif - - case 'j': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - command_jump(&cs, optarg); - break; - - - case 'i': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw.ip.iniface, - cs.fw.ip.iniface_mask); - break; - - case 'o': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw.ip.outiface, - cs.fw.ip.outiface_mask); - break; - - case 'f': - set_option(&cs.options, OPT_FRAGMENT, &invflags, - invert); - cs.fw.ip.flags |= IPT_F_FRAG; - break; - - case 'v': - if (!verbose) - set_option(&cs.options, OPT_VERBOSE, - &invflags, invert); - verbose++; - break; - - case 'w': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-w' from " - "iptables-restore"); - } - wait = parse_wait_time(argc, argv); - break; - - case 'W': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-W' from " - "iptables-restore"); - } - parse_wait_interval(argc, argv, &wait_interval); - wait_interval_set = true; - break; - - case 'm': - command_match(&cs, invert); - break; - - case 'n': - set_option(&cs.options, OPT_NUMERIC, &invflags, - invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - if (restore && table_set) - xtables_error(PARAMETER_PROBLEM, - "The -t option cannot be used in %s.\n", - xt_params->program_name); - *table = optarg; - table_set = true; - break; - - case 'x': - set_option(&cs.options, OPT_EXPANDED, &invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", prog_vers); - else - printf("%s v%s\n", - prog_name, prog_vers); - exit(0); - - case '0': - set_option(&cs.options, OPT_LINENUMBERS, &invflags, - invert); - break; - - case 'M': - xtables_modprobe_program = optarg; - break; - - case 'c': - - set_option(&cs.options, OPT_COUNTERS, &invflags, - invert); - pcnt = optarg; - bcnt = strchr(pcnt + 1, ','); - if (bcnt) - bcnt++; - if (!bcnt && xs_has_arg(argc, argv)) - bcnt = argv[optind++]; - if (!bcnt) - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw.counters.pcnt = cnt; - - if (sscanf(bcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw.counters.bcnt = cnt; - break; - - case '4': - /* This is indeed the IPv4 iptables */ - break; - - case '6': - /* This is not the IPv6 ip6tables */ - if (line != -1) - return 1; /* success: line ignored */ - fprintf(stderr, "This is the IPv4 version of iptables.\n"); - exit_tryhelp(2, line); - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2, line); - - default: - if (command_default(&cs, &iptables_globals, invert)) - /* cf. ip6tables.c */ - continue; - break; - } - invert = false; - } - - if (!wait && wait_interval_set) - xtables_error(PARAMETER_PROBLEM, - "--wait-interval only makes sense with --wait\n"); - - if (strcmp(*table, "nat") == 0 && - ((policy != NULL && strcmp(policy, "DROP") == 0) || - (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) - xtables_error(PARAMETER_PROBLEM, - "\nThe \"nat\" table is not intended for filtering, " - "the use of DROP is therefore inhibited.\n\n"); - - for (matchp = cs.matches; matchp; matchp = matchp->next) - xtables_option_mfcall(matchp->match); - if (cs.target != NULL) - xtables_option_tfcall(cs.target); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - cs.fw.ip.invflags = invflags; - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs.options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(cs.options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; - } - - if (shostnetworkmask) - xtables_ipparse_multiple(shostnetworkmask, &saddrs, - &smasks, &nsaddrs); - - if (dhostnetworkmask) - xtables_ipparse_multiple(dhostnetworkmask, &daddrs, - &dmasks, &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" - " source or destination IP addresses"); - - if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - generic_opt_check(command, cs.options); + do_parse(argc, argv, &p, &cs, &args); + + command = p.command; + chain = p.chain; + *table = p.table; + rulenum = p.rulenum; + policy = p.policy; + newname = p.newname; + verbose = p.verbose; + wait = args.wait; + wait_interval = args.wait_interval; + nsaddrs = args.s.naddrs; + ndaddrs = args.d.naddrs; + saddrs = args.s.addr.v4; + daddrs = args.d.addr.v4; + smasks = args.s.mask.v4; + dmasks = args.d.mask.v4; /* Attempt to acquire the xtables lock */ if (!restore) @@ -1160,26 +762,6 @@ int do_command4(int argc, char *argv[], char **table, || command == CMD_CHECK || command == CMD_INSERT || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs.options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs.options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - if (cs.target && iptc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", @@ -1317,6 +899,9 @@ int do_command4(int argc, char *argv[], char **table, case CMD_SET_POLICY: ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle); break; + case CMD_NONE: + /* do_parse ignored the line (eg: -4 with ip6tables-restore) */ + break; default: /* We should never reach this... */ exit_tryhelp(2, line); diff --git a/iptables/xshared.c b/iptables/xshared.c index a3985d45..8d94fcd5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1864,8 +1864,11 @@ void ipv4_post_parse(int command, struct iptables_command_state *cs, if (args->goto_set) cs->fw.ip.flags |= IPT_F_GOTO; + /* nft-variants use cs->counters, legacy uses cs->fw.counters */ cs->counters.pcnt = args->pcnt_cnt; cs->counters.bcnt = args->bcnt_cnt; + cs->fw.counters.pcnt = args->pcnt_cnt; + cs->fw.counters.bcnt = args->bcnt_cnt; if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { -- cgit v1.2.3 From 5c2c2eea2fff3019f04dd85a489f7186b76d24dd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Nov 2021 23:56:57 +0100 Subject: ip6tables: Use the shared do_parse, too Same change as with iptables, merely have to set IP6T_F_PROTO flag in ipv6_proto_parse(). Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 502 ++++----------------------------------------------- iptables/xshared.c | 4 + 2 files changed, 40 insertions(+), 466 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index b4604f83..560b6ed0 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -90,21 +90,12 @@ static struct option original_opts[] = { struct xtables_globals ip6tables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", + .optstring = OPTSTRING_COMMON "R:S::W::" "46bg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, + .print_help = xtables_printhelp, }; -#define opts ip6tables_globals.opts -#define prog_name ip6tables_globals.program_name -#define prog_vers ip6tables_globals.program_version - -static void -exit_printhelp(const struct xtables_rule_match *matches) -{ - xtables_printhelp(matches); - exit(0); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -114,15 +105,6 @@ exit_printhelp(const struct xtables_rule_match *matches) * return global static data. */ -/* These are invalid numbers as upper layer protocol */ -static int is_exthdr(uint16_t proto) -{ - return (proto == IPPROTO_ROUTING || - proto == IPPROTO_FRAGMENT || - proto == IPPROTO_AH || - proto == IPPROTO_DSTOPTS); -} - static int print_match(const struct xt_entry_match *m, const struct ip6t_ip6 *ip, @@ -714,10 +696,24 @@ generate_entry(const struct ip6t_entry *fw, int do_command6(int argc, char *argv[], char **table, struct xtc_handle **handle, bool restore) { + struct xt_cmd_parse_ops cmd_parse_ops = { + .proto_parse = ipv6_proto_parse, + .post_parse = ipv6_post_parse, + }; + struct xt_cmd_parse p = { + .table = *table, + .restore = restore, + .line = line, + .ops = &cmd_parse_ops, + }; struct iptables_command_state cs = { .jumpto = "", .argv = argv, }; + struct xtables_args args = { + .family = AF_INET6, + .wait_interval.tv_sec = 1, + }; struct ip6t_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in6_addr *saddrs = NULL, *daddrs = NULL; @@ -728,437 +724,28 @@ int do_command6(int argc, char *argv[], char **table, struct timeval wait_interval = { .tv_sec = 1, }; - bool wait_interval_set = false; const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct xtables_match *m; - struct xtables_rule_match *matchp; - struct xtables_target *t; - unsigned long long cnt; - bool table_set = false; - uint16_t invflags = 0; - bool invert = false; - - /* re-set optind to 0 in case do_command6 gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command6 gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = xtables_matches; m; m = m->next) - m->mflags = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - - opts = xt_params->orig_opts; - while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::W::nt:m:xc:g:46", - opts, NULL)) != -1) { - switch (cs.c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, invert); - chain = optarg; - break; - - case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'S': - add_command(&command, CMD_LIST_RULES, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_ZERO_NUM; - } - break; - - case 'N': - parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* ip6tables -p icmp -h */ - if (!cs.matches && cs.protocol) - xtables_find_match(cs.protocol, XTF_TRY_LOAD, - &cs.matches); - - exit_printhelp(cs.matches); - - /* - * Option selection - */ - case 'p': - set_option(&cs.options, OPT_PROTOCOL, &invflags, - invert); - - /* Canonicalize into lower case */ - for (cs.protocol = optarg; *cs.protocol; cs.protocol++) - *cs.protocol = tolower(*cs.protocol); - - cs.protocol = optarg; - cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol); - cs.fw6.ipv6.flags |= IP6T_F_PROTO; - - if (cs.fw6.ipv6.proto == 0 && (invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - - if (is_exthdr(cs.fw6.ipv6.proto) - && (invflags & XT_INV_PROTO) == 0) - fprintf(stderr, - "Warning: never matched protocol: %s. " - "use extension match instead.\n", - cs.protocol); - break; - - case 's': - set_option(&cs.options, OPT_SOURCE, &invflags, invert); - shostnetworkmask = optarg; - break; - - case 'd': - set_option(&cs.options, OPT_DESTINATION, &invflags, - invert); - dhostnetworkmask = optarg; - break; - -#ifdef IP6T_F_GOTO - case 'g': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - cs.fw6.ipv6.flags |= IP6T_F_GOTO; - cs.jumpto = xt_parse_target(optarg); - break; -#endif - - case 'j': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - command_jump(&cs, optarg); - break; - - case 'i': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw6.ipv6.iniface, - cs.fw6.ipv6.iniface_mask); - break; - - case 'o': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw6.ipv6.outiface, - cs.fw6.ipv6.outiface_mask); - break; - - case 'v': - if (!verbose) - set_option(&cs.options, OPT_VERBOSE, - &invflags, invert); - verbose++; - break; - - case 'w': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-w' from " - "ip6tables-restore"); - } - wait = parse_wait_time(argc, argv); - break; - - case 'W': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-W' from " - "ip6tables-restore"); - } - parse_wait_interval(argc, argv, &wait_interval); - wait_interval_set = true; - break; - - case 'm': - command_match(&cs, invert); - break; - - case 'n': - set_option(&cs.options, OPT_NUMERIC, &invflags, invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - if (restore && table_set) - xtables_error(PARAMETER_PROBLEM, - "The -t option cannot be used in %s.\n", - xt_params->program_name); - *table = optarg; - table_set = true; - break; - - case 'x': - set_option(&cs.options, OPT_EXPANDED, &invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", prog_vers); - else - printf("%s v%s\n", - prog_name, prog_vers); - exit(0); - - case '0': - set_option(&cs.options, OPT_LINENUMBERS, &invflags, - invert); - break; - - case 'M': - xtables_modprobe_program = optarg; - break; - - case 'c': - - set_option(&cs.options, OPT_COUNTERS, &invflags, - invert); - pcnt = optarg; - bcnt = strchr(pcnt + 1, ','); - if (bcnt) - bcnt++; - if (!bcnt && xs_has_arg(argc, argv)) - bcnt = argv[optind++]; - if (!bcnt) - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw6.counters.pcnt = cnt; - - if (sscanf(bcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw6.counters.bcnt = cnt; - break; - - case '4': - /* This is not the IPv4 iptables */ - if (line != -1) - return 1; /* success: line ignored */ - fprintf(stderr, "This is the IPv6 version of ip6tables.\n"); - exit_tryhelp(2, line); - - case '6': - /* This is indeed the IPv6 ip6tables */ - break; - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2, line); - - default: - if (command_default(&cs, &ip6tables_globals, invert)) - /* - * If new options were loaded, we must retry - * getopt immediately and not allow - * invert=false to be executed. - */ - continue; - break; - } - invert = false; - } - - if (!wait && wait_interval_set) - xtables_error(PARAMETER_PROBLEM, - "--wait-interval only makes sense with --wait\n"); - - if (strcmp(*table, "nat") == 0 && - ((policy != NULL && strcmp(policy, "DROP") == 0) || - (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) - xtables_error(PARAMETER_PROBLEM, - "\nThe \"nat\" table is not intended for filtering, " - "the use of DROP is therefore inhibited.\n\n"); - - for (matchp = cs.matches; matchp; matchp = matchp->next) - xtables_option_mfcall(matchp->match); - if (cs.target != NULL) - xtables_option_tfcall(cs.target); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - cs.fw6.ipv6.invflags = invflags; - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs.options & OPT_DESTINATION)) - dhostnetworkmask = "::0/0"; - if (!(cs.options & OPT_SOURCE)) - shostnetworkmask = "::0/0"; - } - - if (shostnetworkmask) - xtables_ip6parse_multiple(shostnetworkmask, &saddrs, - &smasks, &nsaddrs); - - if (dhostnetworkmask) - xtables_ip6parse_multiple(dhostnetworkmask, &daddrs, - &dmasks, &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" - " source or destination IP addresses"); - - if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - generic_opt_check(command, cs.options); + do_parse(argc, argv, &p, &cs, &args); + + command = p.command; + chain = p.chain; + *table = p.table; + rulenum = p.rulenum; + policy = p.policy; + newname = p.newname; + verbose = p.verbose; + wait = args.wait; + wait_interval = args.wait_interval; + nsaddrs = args.s.naddrs; + ndaddrs = args.d.naddrs; + saddrs = args.s.addr.v6; + daddrs = args.d.addr.v6; + smasks = args.s.mask.v6; + dmasks = args.d.mask.v6; /* Attempt to acquire the xtables lock */ if (!restore) @@ -1182,26 +769,6 @@ int do_command6(int argc, char *argv[], char **table, || command == CMD_CHECK || command == CMD_INSERT || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs.options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs.options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", @@ -1337,6 +904,9 @@ int do_command6(int argc, char *argv[], char **table, case CMD_SET_POLICY: ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle); break; + case CMD_NONE: + /* do_parse ignored the line (eg: -4 with ip6tables-restore) */ + break; default: /* We should never reach this... */ exit_tryhelp(2, line); diff --git a/iptables/xshared.c b/iptables/xshared.c index 8d94fcd5..c5a93290 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1836,6 +1836,10 @@ void ipv6_proto_parse(struct iptables_command_state *cs, cs->fw6.ipv6.proto = args->proto; cs->fw6.ipv6.invflags = args->invflags; + /* this is needed for ip6tables-legacy only */ + args->flags |= IP6T_F_PROTO; + cs->fw6.ipv6.flags |= IP6T_F_PROTO; + if (is_exthdr(cs->fw6.ipv6.proto) && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0) fprintf(stderr, -- cgit v1.2.3 From 223f02ca9dbe991cbade5cd88c0bf1f3c93538af Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 18:41:35 +0100 Subject: nft: fix indentation error. `add_action` was indented with 7 spaces. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables/nft.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 887c735b..daab1b4a 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1335,27 +1335,27 @@ int add_verdict(struct nftnl_rule *r, int verdict) int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set) { - int ret = 0; - - /* If no target at all, add nothing (default to continue) */ - if (cs->target != NULL) { - /* Standard target? */ - if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) - ret = add_verdict(r, NF_ACCEPT); - else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) - ret = add_verdict(r, NF_DROP); - else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) - ret = add_verdict(r, NFT_RETURN); - else - ret = add_target(r, cs->target->t); - } else if (strlen(cs->jumpto) > 0) { - /* Not standard, then it's a go / jump to chain */ - if (goto_set) - ret = add_jumpto(r, cs->jumpto, NFT_GOTO); - else - ret = add_jumpto(r, cs->jumpto, NFT_JUMP); - } - return ret; + int ret = 0; + + /* If no target at all, add nothing (default to continue) */ + if (cs->target != NULL) { + /* Standard target? */ + if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) + ret = add_verdict(r, NF_ACCEPT); + else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) + ret = add_verdict(r, NF_DROP); + else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) + ret = add_verdict(r, NFT_RETURN); + else + ret = add_target(r, cs->target->t); + } else if (strlen(cs->jumpto) > 0) { + /* Not standard, then it's a go / jump to chain */ + if (goto_set) + ret = add_jumpto(r, cs->jumpto, NFT_GOTO); + else + ret = add_jumpto(r, cs->jumpto, NFT_JUMP); + } + return ret; } static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh) -- cgit v1.2.3 From 7ee5b97095365383629b9c7c78ba93e09e1051d2 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 18:41:42 +0100 Subject: tests: iptables-test: correct misspelt variable "EXECUTEABLE" -> "EXECUTABLE" Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables-test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 0ba3d368..95fa11b1 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -84,7 +84,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): cmd = iptables + " -A " + rule if netns: - cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + cmd + cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + cmd ret = execute_cmd(cmd, filename, lineno) @@ -123,7 +123,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): elif splitted[0] == EBTABLES: command = EBTABLES_SAVE - command = EXECUTEABLE + " " + command + command = EXECUTABLE + " " + command if netns: command = "ip netns exec ____iptables-container-test " + command @@ -168,7 +168,7 @@ def execute_cmd(cmd, filename, lineno): ''' global log_file if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '): - cmd = EXECUTEABLE + " " + cmd + cmd = EXECUTABLE + " " + cmd print("command: {}".format(cmd), file=log_file) ret = subprocess.call(cmd, shell=True, universal_newlines=True, @@ -202,12 +202,12 @@ def run_test_file(filename, netns): iptables = IPTABLES elif "libarpt_" in filename: # only supported with nf_tables backend - if EXECUTEABLE != "xtables-nft-multi": + if EXECUTABLE != "xtables-nft-multi": return 0, 0 iptables = ARPTABLES elif "libebt_" in filename: # only supported with nf_tables backend - if EXECUTEABLE != "xtables-nft-multi": + if EXECUTABLE != "xtables-nft-multi": return 0, 0 iptables = EBTABLES else: @@ -245,7 +245,7 @@ def run_test_file(filename, netns): if line[0] == "%": external_cmd = line.rstrip()[1:] if netns: - external_cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + external_cmd + external_cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + external_cmd execute_cmd(external_cmd, filename, lineno) continue @@ -366,10 +366,10 @@ def main(): show_missing() return - global EXECUTEABLE - EXECUTEABLE = "xtables-legacy-multi" + global EXECUTABLE + EXECUTABLE = "xtables-legacy-multi" if args.nftables: - EXECUTEABLE = "xtables-nft-multi" + EXECUTABLE = "xtables-nft-multi" if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) -- cgit v1.2.3 From 30b178b9bf11e75cd5ff7310ce0f5d9c9ace3b7a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 8 Jan 2022 13:15:20 +0100 Subject: extensions: *NAT: Kill multiple IPv4 range support It is the year of the great revolution, nobody cares about kernel versions below 2.6.11 anymore. Time to get rid of the cruft. While being at it, drop the explicit duplicate argument check and instead just remove XTOPT_MULTI flag from the respective xt_option_entry. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- extensions/libipt_DNAT.c | 138 ++++++++++++++-------------------------- extensions/libipt_SNAT.c | 158 +++++++++++++++++----------------------------- extensions/libxt_DNAT.man | 6 -- extensions/libxt_SNAT.man | 6 -- 4 files changed, 106 insertions(+), 202 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index 5b33fd23..eefa95eb 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -18,14 +18,6 @@ enum { F_X_TO_DEST = 1 << O_X_TO_DEST, }; -/* Dest NAT data consists of a multi-range, indicating where to map - to. */ -struct ipt_natinfo -{ - struct xt_entry_target t; - struct nf_nat_ipv4_multi_range_compat mr; -}; - static void DNAT_help(void) { printf( @@ -46,41 +38,20 @@ static void DNAT_help_v2(void) static const struct xt_option_entry DNAT_opts[] = { {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, + .flags = XTOPT_MAND}, {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, XTOPT_TABLEEND, }; -static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) -{ - unsigned int size; - - /* One rangesize already in struct ipt_natinfo */ - size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); - - info = realloc(info, size); - if (!info) - xtables_error(OTHER_PROBLEM, "Out of memory\n"); - - info->t.u.target_size = size; - info->mr.range[info->mr.rangesize] = *range; - info->mr.rangesize++; - - return info; -} - /* Ranges expected in network order. */ -static struct xt_entry_target * -parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) +static void +parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range) { - struct nf_nat_ipv4_range range; char *arg, *colon, *dash, *error; const struct in_addr *ip; arg = xtables_strdup(orig_arg); - memset(&range, 0, sizeof(range)); colon = strchr(arg, ':'); if (colon) { @@ -90,7 +61,7 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; port = atoi(colon+1); if (port <= 0 || port > 65535) @@ -104,8 +75,8 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) dash = strchr(colon, '-'); if (!dash) { - range.min.tcp.port - = range.max.tcp.port + range->min.tcp.port + = range->max.tcp.port = htons(port); } else { int maxport; @@ -118,18 +89,18 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) /* People are stupid. */ xtables_error(PARAMETER_PROBLEM, "Port range `%s' funky\n", colon+1); - range.min.tcp.port = htons(port); - range.max.tcp.port = htons(maxport); + range->min.tcp.port = htons(port); + range->max.tcp.port = htons(maxport); } /* Starts with a colon? No IP info...*/ if (colon == arg) { free(arg); - return &(append_range(info, &range)->t); + return; } *colon = '\0'; } - range.flags |= NF_NAT_RANGE_MAP_IPS; + range->flags |= NF_NAT_RANGE_MAP_IPS; dash = strchr(arg, '-'); if (colon && dash && dash > colon) dash = NULL; @@ -141,24 +112,24 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) if (!ip) xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", arg); - range.min_ip = ip->s_addr; + range->min_ip = ip->s_addr; if (dash) { ip = xtables_numeric_to_ipaddr(dash+1); if (!ip) xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", dash+1); - range.max_ip = ip->s_addr; + range->max_ip = ip->s_addr; } else - range.max_ip = range.min_ip; + range->max_ip = range->min_ip; free(arg); - return &(append_range(info, &range)->t); + return; } static void DNAT_parse(struct xt_option_call *cb) { + struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; const struct ipt_entry *entry = cb->xt_entry; - struct ipt_natinfo *info = (void *)(*cb->target); int portok; if (entry->ip.proto == IPPROTO_TCP @@ -173,18 +144,11 @@ static void DNAT_parse(struct xt_option_call *cb) xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - if (!kernel_version) - get_kernel_version(); - if (kernel_version > LINUX_VERSION(2, 6, 10)) - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } - *cb->target = parse_to(cb->arg, portok, info); + parse_to(cb->arg, portok, mr->range); cb->xflags |= F_X_TO_DEST; break; case O_PERSISTENT: - info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; + mr->range->flags |= NF_NAT_RANGE_PERSISTENT; break; } } @@ -196,6 +160,8 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) if ((cb->xflags & f) == f) mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + + mr->rangesize = 1; } static void print_range(const struct nf_nat_ipv4_range *r) @@ -221,32 +187,28 @@ static void print_range(const struct nf_nat_ipv4_range *r) static void DNAT_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)target->data; printf(" to:"); - for (i = 0; i < info->mr.rangesize; i++) { - print_range(&info->mr.range[i]); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); - } + print_range(mr->range); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); } static void DNAT_save(const void *ip, const struct xt_entry_target *target) { - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - for (i = 0; i < info->mr.rangesize; i++) { - printf(" --to-destination "); - print_range(&info->mr.range[i]); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); - } + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)target->data; + + printf(" --to-destination "); + print_range(mr->range); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); } static void print_range_xlate(const struct nf_nat_ipv4_range *r, @@ -272,23 +234,21 @@ static void print_range_xlate(const struct nf_nat_ipv4_range *r, static int DNAT_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct ipt_natinfo *info = (const void *)params->target; - unsigned int i = 0; + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)params->target->data; bool sep_need = false; const char *sep = " "; - for (i = 0; i < info->mr.rangesize; i++) { - xt_xlate_add(xl, "dnat to "); - print_range_xlate(&info->mr.range[i], xl); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } + xt_xlate_add(xl, "dnat to "); + print_range_xlate(mr->range, xl); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, " random"); + sep_need = true; + } + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) { + if (sep_need) + sep = ","; + xt_xlate_add(xl, "%spersistent", sep); } return 1; @@ -406,10 +366,6 @@ static void DNAT_parse_v2(struct xt_option_call *cb) xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } parse_to_v2(cb->arg, portok, range); cb->xflags |= F_X_TO_DEST; break; diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index c655439e..bd36830a 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -20,14 +20,6 @@ enum { F_X_TO_SRC = 1 << O_X_TO_SRC, }; -/* Source NAT data consists of a multi-range, indicating where to map - to. */ -struct ipt_natinfo -{ - struct xt_entry_target t; - struct nf_nat_ipv4_multi_range_compat mr; -}; - static void SNAT_help(void) { printf( @@ -39,42 +31,21 @@ static void SNAT_help(void) static const struct xt_option_entry SNAT_opts[] = { {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, + .flags = XTOPT_MAND}, {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, XTOPT_TABLEEND, }; -static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) -{ - unsigned int size; - - /* One rangesize already in struct ipt_natinfo */ - size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); - - info = realloc(info, size); - if (!info) - xtables_error(OTHER_PROBLEM, "Out of memory\n"); - - info->t.u.target_size = size; - info->mr.range[info->mr.rangesize] = *range; - info->mr.rangesize++; - - return info; -} - /* Ranges expected in network order. */ -static struct xt_entry_target * -parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) +static void +parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range) { - struct nf_nat_ipv4_range range; char *arg, *colon, *dash, *error; const struct in_addr *ip; arg = xtables_strdup(orig_arg); - memset(&range, 0, sizeof(range)); colon = strchr(arg, ':'); if (colon) { @@ -84,7 +55,7 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; port = atoi(colon+1); if (port <= 0 || port > 65535) @@ -98,8 +69,8 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) dash = strchr(colon, '-'); if (!dash) { - range.min.tcp.port - = range.max.tcp.port + range->min.tcp.port + = range->max.tcp.port = htons(port); } else { int maxport; @@ -112,18 +83,18 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) /* People are stupid. */ xtables_error(PARAMETER_PROBLEM, "Port range `%s' funky\n", colon+1); - range.min.tcp.port = htons(port); - range.max.tcp.port = htons(maxport); + range->min.tcp.port = htons(port); + range->max.tcp.port = htons(maxport); } /* Starts with a colon? No IP info...*/ if (colon == arg) { free(arg); - return &(append_range(info, &range)->t); + return; } *colon = '\0'; } - range.flags |= NF_NAT_RANGE_MAP_IPS; + range->flags |= NF_NAT_RANGE_MAP_IPS; dash = strchr(arg, '-'); if (colon && dash && dash > colon) dash = NULL; @@ -135,24 +106,24 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) if (!ip) xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", arg); - range.min_ip = ip->s_addr; + range->min_ip = ip->s_addr; if (dash) { ip = xtables_numeric_to_ipaddr(dash+1); if (!ip) xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", dash+1); - range.max_ip = ip->s_addr; + range->max_ip = ip->s_addr; } else - range.max_ip = range.min_ip; + range->max_ip = range->min_ip; free(arg); - return &(append_range(info, &range)->t); + return; } static void SNAT_parse(struct xt_option_call *cb) { + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; const struct ipt_entry *entry = cb->xt_entry; - struct ipt_natinfo *info = (void *)(*cb->target); int portok; if (entry->ip.proto == IPPROTO_TCP @@ -167,18 +138,11 @@ static void SNAT_parse(struct xt_option_call *cb) xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_SRC: - if (cb->xflags & F_X_TO_SRC) { - if (!kernel_version) - get_kernel_version(); - if (kernel_version > LINUX_VERSION(2, 6, 10)) - xtables_error(PARAMETER_PROBLEM, - "SNAT: Multiple --to-source not supported"); - } - *cb->target = parse_to(cb->arg, portok, info); + parse_to(cb->arg, portok, mr->range); cb->xflags |= F_X_TO_SRC; break; case O_PERSISTENT: - info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; + mr->range->flags |= NF_NAT_RANGE_PERSISTENT; break; } } @@ -190,9 +154,11 @@ static void SNAT_fcheck(struct xt_fcheck_call *cb) struct nf_nat_ipv4_multi_range_compat *mr = cb->data; if ((cb->xflags & f) == f) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM; if ((cb->xflags & r) == r) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + + mr->rangesize = 1; } static void print_range(const struct nf_nat_ipv4_range *r) @@ -218,36 +184,32 @@ static void print_range(const struct nf_nat_ipv4_range *r) static void SNAT_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)target->data; printf(" to:"); - for (i = 0; i < info->mr.rangesize; i++) { - print_range(&info->mr.range[i]); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); - } + print_range(mr->range); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" random-fully"); + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); } static void SNAT_save(const void *ip, const struct xt_entry_target *target) { - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - for (i = 0; i < info->mr.rangesize; i++) { - printf(" --to-source "); - print_range(&info->mr.range[i]); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); - } + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)target->data; + + printf(" --to-source "); + print_range(mr->range); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" --random-fully"); + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); } static void print_range_xlate(const struct nf_nat_ipv4_range *r, @@ -274,29 +236,27 @@ static void print_range_xlate(const struct nf_nat_ipv4_range *r, static int SNAT_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct ipt_natinfo *info = (const void *)params->target; - unsigned int i = 0; + const struct nf_nat_ipv4_multi_range_compat *mr = + (const void *)params->target->data; bool sep_need = false; const char *sep = " "; - for (i = 0; i < info->mr.rangesize; i++) { - xt_xlate_add(xl, "snat to "); - print_range_xlate(&info->mr.range[i], xl); - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%sfully-random", sep); - sep_need = true; - } - if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } + xt_xlate_add(xl, "snat to "); + print_range_xlate(mr->range, xl); + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, " random"); + sep_need = true; + } + if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { + if (sep_need) + sep = ","; + xt_xlate_add(xl, "%sfully-random", sep); + sep_need = true; + } + if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) { + if (sep_need) + sep = ","; + xt_xlate_add(xl, "%spersistent", sep); } return 1; diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man index 225274ff..c3daea9a 100644 --- a/extensions/libxt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -18,12 +18,6 @@ if the rule also specifies one of the following protocols: If no port range is specified, then the destination port will never be modified. If no IP address is specified then only the destination port will be modified. -In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For -those kernels, if you specify more than one destination address, either via an -address range or multiple \-\-to\-destination options, a simple round-robin (one -after another in cycle) load balancing takes place between these addresses. -Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges -anymore. .TP \fB\-\-random\fP If option diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man index 8cd0b80e..08766447 100644 --- a/extensions/libxt_SNAT.man +++ b/extensions/libxt_SNAT.man @@ -19,12 +19,6 @@ If no port range is specified, then source ports below 512 will be mapped to other ports below 512: those between 512 and 1023 inclusive will be mapped to ports below 1024, and other ports will be mapped to 1024 or above. Where possible, no port alteration will occur. -In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those -kernels, if you specify more than one source address, either via an address -range or multiple \-\-to\-source options, a simple round-robin (one after another -in cycle) takes place between these addresses. -Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges -anymore. .TP \fB\-\-random\fP If option -- cgit v1.2.3 From db99f6019eab5f108fe1050349b3e793ea21353d Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Fri, 1 Oct 2021 18:41:36 +0100 Subject: extensions: libxt_NFLOG: use nft built-in logging instead of xt_NFLOG Replaces the use of xt_NFLOG with the nft built-in log statement. This additionally adds support for using longer log prefixes of 128 characters in size. Until now NFLOG has truncated the log-prefix to the 64-character limit supported by iptables-legacy. We now use the struct xtables_target's udata member to store the longer 128-character prefix supported by iptables-nft. Signed-off-by: Kyle Bowman Signed-off-by: Alex Forster Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.c | 6 ++++++ iptables/nft.c | 28 ++++++++++++++++++++++++++++ iptables/nft.h | 1 + 3 files changed, 35 insertions(+) diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 02a1b4aa..2b78e278 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -53,12 +54,16 @@ static void NFLOG_init(struct xt_entry_target *t) static void NFLOG_parse(struct xt_option_call *cb) { + char *nf_log_prefix = cb->udata; + xtables_option_parse(cb); switch (cb->entry->id) { case O_PREFIX: if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --log-prefix"); + + snprintf(nf_log_prefix, NF_LOG_PREFIXLEN, "%s", cb->arg); break; } } @@ -149,6 +154,7 @@ static struct xtables_target nflog_target = { .save = NFLOG_save, .x6_options = NFLOG_opts, .xlate = NFLOG_xlate, + .udata_size = NF_LOG_PREFIXLEN }; void _init(void) diff --git a/iptables/nft.c b/iptables/nft.c index daab1b4a..e4932a7a 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -1346,6 +1347,8 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, ret = add_verdict(r, NF_DROP); else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) ret = add_verdict(r, NFT_RETURN); + else if (strcmp(cs->jumpto, "NFLOG") == 0) + ret = add_log(r, cs); else ret = add_target(r, cs->target->t); } else if (strlen(cs->jumpto) > 0) { @@ -1358,6 +1361,31 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, return ret; } +int add_log(struct nftnl_rule *r, struct iptables_command_state *cs) +{ + struct nftnl_expr *expr; + struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data; + + expr = nftnl_expr_alloc("log"); + if (!expr) + return -ENOMEM; + + if (info->prefix[0] != '\0') + nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX, + cs->target->udata); + + nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group); + if (info->flags & XT_NFLOG_F_COPY_LEN) + nftnl_expr_set_u32(expr, NFTNL_EXPR_LOG_SNAPLEN, + info->len); + if (info->threshold) + nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_QTHRESHOLD, + info->threshold); + + nftnl_rule_add_expr(r, expr); + return 0; +} + static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh) { #ifdef NLDEBUG diff --git a/iptables/nft.h b/iptables/nft.h index f189b03f..4c78f761 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -194,6 +194,7 @@ int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match 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_log(struct nftnl_rule *r, struct iptables_command_state *cs); char *get_comment(const void *data, uint32_t data_len); enum nft_rule_print { -- cgit v1.2.3 From 62ad29e9b778f4419573c6b43fe7a0a00d783fe6 Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Fri, 1 Oct 2021 18:41:37 +0100 Subject: extensions: libxt_NFLOG: don't truncate log prefix on print/save When parsing the rule, use a struct with a layout compatible to that of struct xt_nflog_info, but with a buffer large enough to contain the whole 128-character nft prefix. We always send the nflog-group to the kernel since, for nft, log and nflog targets are handled by the same kernel module, and are distinguished by whether they define an nflog-group. Therefore, we must send the group even if it is zero, or the kernel will configure the target as a log, not an nflog. Changes to nft_is_expr_compatible were made since only targets which have an `nflog-group` are compatible. Since nflog targets are distinguished by having an nflog-group, we ignore targets without one. We also set the copy-len flag if the snap-len is set since without this, iptables will mistake `nflog-size` for `nflog-range`. Signed-off-by: Kyle Bowman Signed-off-by: Alex Forster Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ iptables/nft.c | 4 ++++ 2 files changed, 56 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 4394e8b7..d0d0d558 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -20,8 +20,10 @@ #include +#include #include #include +#include #include #include @@ -580,6 +582,54 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->h->ops->parse_match(match, ctx->cs); } +static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xtables_target *target; + struct xt_entry_target *t; + size_t target_size; + /* + * In order to handle the longer log-prefix supported by nft, instead of + * using struct xt_nflog_info, we use a struct with a compatible layout, but + * a larger buffer for the prefix. + */ + struct xt_nflog_info_nft { + __u32 len; + __u16 group; + __u16 threshold; + __u16 flags; + __u16 pad; + char prefix[NF_LOG_PREFIXLEN]; + } info = { + .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), + .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), + }; + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { + info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); + info.flags = XT_NFLOG_F_COPY_LEN; + } + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX)) + snprintf(info.prefix, sizeof(info.prefix), "%s", + nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); + + target = xtables_find_target("NFLOG", XTF_TRY_LOAD); + if (target == NULL) + return; + + target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + + XT_ALIGN(sizeof(struct xt_nflog_info_nft)); + + t = xtables_calloc(1, target_size); + t->u.target_size = target_size; + strcpy(t->u.user.name, target->name); + t->u.user.revision = target->revision; + + target->t = t; + + memcpy(&target->t->data, &info, sizeof(info)); + + ctx->h->ops->parse_target(target, ctx->cs); +} + static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, struct nftnl_expr *e) { @@ -629,6 +679,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, nft_parse_limit(&ctx, expr); else if (strcmp(name, "lookup") == 0) nft_parse_lookup(&ctx, h, expr); + else if (strcmp(name, "log") == 0) + nft_parse_log(&ctx, expr); expr = nftnl_expr_iter_next(iter); } diff --git a/iptables/nft.c b/iptables/nft.c index e4932a7a..72f7cf13 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3542,6 +3542,10 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data) nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0) return 0; + if (!strcmp(name, "log") && + nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_GROUP)) + return 0; + return -1; } -- cgit v1.2.3 From f9df828a46c7446c8e894be7ae45a2ac97b4a278 Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Fri, 1 Oct 2021 18:41:38 +0100 Subject: extensions: libxt_NFLOG: disable `--nflog-range` Python test-cases nft has no equivalent to `--nflog-range`, so we cannot emulate it and the Python unit-tests for it fail. However, since `--nflog-range` is broken and doesn't do anything, the tests are not testing anything useful. Signed-off-by: Kyle Bowman Signed-off-by: Alex Forster Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.t | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t index 933fa221..eefb058b 100644 --- a/extensions/libxt_NFLOG.t +++ b/extensions/libxt_NFLOG.t @@ -3,10 +3,12 @@ -j NFLOG --nflog-group 65535;=;OK -j NFLOG --nflog-group 65536;;FAIL -j NFLOG --nflog-group 0;-j NFLOG;OK --j NFLOG --nflog-range 1;=;OK --j NFLOG --nflog-range 4294967295;=;OK --j NFLOG --nflog-range 4294967296;;FAIL --j NFLOG --nflog-range -1;;FAIL +# `--nflog-range` is broken and only supported by xtables-legacy. It +# has been superseded by `--nflog--group`. +# -j NFLOG --nflog-range 1;=;OK +# -j NFLOG --nflog-range 4294967295;=;OK +# -j NFLOG --nflog-range 4294967296;;FAIL +# -j NFLOG --nflog-range -1;;FAIL -j NFLOG --nflog-size 0;=;OK -j NFLOG --nflog-size 1;=;OK -j NFLOG --nflog-size 4294967295;=;OK -- cgit v1.2.3 From f0d02998883d2efcb316cd6f524e2f7b3c4d055b Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 18:41:39 +0100 Subject: extensions: libxt_NFLOG: fix `--nflog-prefix` Python test-cases The `iptables-save` includes an extra space between `--nflog-prefix` and the prefix. The maximum length of prefixes includes the trailing NUL character. NFLOG silently truncates prefixes which exceed the maximum length. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.t | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t index eefb058b..13bbf2bf 100644 --- a/extensions/libxt_NFLOG.t +++ b/extensions/libxt_NFLOG.t @@ -14,10 +14,8 @@ -j NFLOG --nflog-size 4294967295;=;OK -j NFLOG --nflog-size 4294967296;;FAIL -j NFLOG --nflog-size -1;;FAIL -# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...] -# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK -# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...] -# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL +-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK +-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK -j NFLOG --nflog-threshold 1;=;OK # ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0 # -j NFLOG --nflog-threshold 0;;FAIL -- cgit v1.2.3 From 05286bab77a6e0f9502e8fb99e1c53ed15663f3f Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 18:41:40 +0100 Subject: extensions: libxt_NFLOG: remove extra space when saving targets with prefixes When printing out NFLOG targets an extra space was inserted between `--nflog-prefix` and the prefix itself: $ sudo /usr/sbin/iptables -A INPUT -j NFLOG --nflog-prefix test $ sudo /usr/sbin/iptables-save | grep NFLOG -A INPUT -j NFLOG --nflog-prefix test ^^ Fixes: 73866357e4a7 ("iptables: do not print trailing whitespaces") Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.c | 2 +- extensions/libxt_NFLOG.t | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 2b78e278..6137a68f 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -83,7 +83,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb) static void nflog_print(const struct xt_nflog_info *info, char *prefix) { if (info->prefix[0] != '\0') { - printf(" %snflog-prefix ", prefix); + printf(" %snflog-prefix", prefix); xtables_save_string(info->prefix); } if (info->group) diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t index 13bbf2bf..561ec8c7 100644 --- a/extensions/libxt_NFLOG.t +++ b/extensions/libxt_NFLOG.t @@ -14,8 +14,8 @@ -j NFLOG --nflog-size 4294967295;=;OK -j NFLOG --nflog-size 4294967296;;FAIL -j NFLOG --nflog-size -1;;FAIL --j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK --j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK +-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK +-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK -j NFLOG --nflog-threshold 1;=;OK # ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0 # -j NFLOG --nflog-threshold 0;;FAIL -- cgit v1.2.3 From b32ae771c8cd7f0b72e4e21cd7d388c745fbae41 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Fri, 1 Oct 2021 18:41:41 +0100 Subject: build: replace `AM_PROG_LIBTOOL` and `AC_DISABLE_STATIC` with `LT_INIT` `AM_PROG_LIBTOOL` is superseded by `LT_INIT`, which also accepts options to control the defaults for creating shared or static libraries. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 00ae60c5..86c67194 100644 --- a/configure.ac +++ b/configure.ac @@ -12,9 +12,8 @@ AC_PROG_INSTALL AM_INIT_AUTOMAKE([-Wall]) AC_PROG_CC AM_PROG_CC_C_O -AC_DISABLE_STATIC m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) -AM_PROG_LIBTOOL +LT_INIT([disable-static]) AC_ARG_WITH([kernel], AS_HELP_STRING([--with-kernel=PATH], -- cgit v1.2.3 From 26ecdf53960658771c0fc582f72a4025e2887f75 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 18 Jan 2022 22:39:08 +0100 Subject: xshared: Fix response to unprivileged users Expected behaviour in both variants is: * Print help without error, append extension help if -m and/or -j options are present * Indicate lack of permissions in an error message for anything else With iptables-nft, this was broken basically from day 1. Shared use of do_parse() then somewhat broke legacy: it started complaining about inability to create a lock file. Fix this by making iptables-nft assume extension revision 0 is present if permissions don't allow to verify. This is consistent with legacy. Second part is to exit directly after printing help - this avoids having to make the following code "nop-aware" to prevent privileged actions. Signed-off-by: Phil Sutter Reviewed-by: Florian Westphal --- iptables/nft.c | 5 ++ .../shell/testcases/iptables/0008-unprivileged_0 | 60 ++++++++++++++++++++++ iptables/xshared.c | 3 +- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100755 iptables/tests/shell/testcases/iptables/0008-unprivileged_0 diff --git a/iptables/nft.c b/iptables/nft.c index 72f7cf13..b5de687c 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3312,6 +3312,11 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt) err: mnl_socket_close(nl); + /* pretend revision 0 is valid if not permitted to check - + * this is required for printing extension help texts as user */ + if (ret < 0 && errno == EPERM && rev == 0) + return 1; + return ret < 0 ? 0 : 1; } diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 new file mode 100755 index 00000000..43e3bc87 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 @@ -0,0 +1,60 @@ +#!/bin/bash + +# iptables may print match/target specific help texts +# help output should work for unprivileged users + +run() { + echo "running: $*" >&2 + runuser -u nobody -- "$@" +} + +grep_or_rc() { + declare -g rc + grep -q "$*" && return 0 + echo "missing in output: $*" >&2 + return 1 +} + +out=$(run $XT_MULTI iptables --help) +let "rc+=$?" +grep_or_rc "iptables -h (print this help information)" <<< "$out" +let "rc+=$?" + +out=$(run $XT_MULTI iptables -m limit --help) +let "rc+=$?" +grep_or_rc "limit match options:" <<< "$out" +let "rc+=$?" + +out=$(run $XT_MULTI iptables -p tcp --help) +let "rc+=$?" +grep_or_rc "tcp match options:" <<< "$out" +let "rc+=$?" + +out=$(run $XT_MULTI iptables -j DNAT --help) +let "rc+=$?" +grep_or_rc "DNAT target options:" <<< "$out" +let "rc+=$?" + +out=$(run $XT_MULTI iptables -p tcp -j DNAT --help) +let "rc+=$?" +grep_or_rc "tcp match options:" <<< "$out" +let "rc+=$?" +out=$(run $XT_MULTI iptables -p tcp -j DNAT --help) +let "rc+=$?" +grep_or_rc "DNAT target options:" <<< "$out" +let "rc+=$?" + + +run $XT_MULTI iptables -L 2>&1 | \ + grep_or_rc "Permission denied" +let "rc+=$?" + +run $XT_MULTI iptables -A FORWARD -p tcp --dport 123 2>&1 | \ + grep_or_rc "Permission denied" +let "rc+=$?" + +run $XT_MULTI iptables -A FORWARD -j DNAT --to-destination 1.2.3.4 2>&1 | \ + grep_or_rc "Permission denied" +let "rc+=$?" + +exit $rc diff --git a/iptables/xshared.c b/iptables/xshared.c index c5a93290..1fd7acc9 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1473,8 +1473,7 @@ void do_parse(int argc, char *argv[], XTF_TRY_LOAD, &cs->matches); xt_params->print_help(cs->matches); - p->command = CMD_NONE; - return; + exit(0); /* * Option selection -- cgit v1.2.3 From ea5d45dc23a4529a2a45c59ac6c13b61297c789e Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Thu, 20 Jan 2022 10:54:05 +0000 Subject: extensions: libxt_NFLOG: fix typo The deprecation warning for `--nflog-range` contains a spelling mistake. Fix it. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 6137a68f..7a12e5ac 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -74,7 +74,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb) if (cb->xflags & F_RANGE) fprintf(stderr, "warn: --nflog-range has never worked and is no" - " longer supported, please use --nflog-size insted\n"); + " longer supported, please use --nflog-size instead\n"); if (cb->xflags & F_SIZE) info->flags |= XT_NFLOG_F_COPY_LEN; -- cgit v1.2.3 From 250dce876d924b9467ffa035af445912e86ea93b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:55 +0100 Subject: nft-shared: support native tcp port delinearize This extends iptables-nft dissector to decode native tcp port matching. nft ruleset: table ip filter { chain INPUT { type filter hook input priority filter; policy accept; tcp sport 12345 tcp sport 12345 tcp dport 6789 tcp sport < 1024 tcp dport >= 1024 } } $ iptables-nft-save -A INPUT -p tcp -m tcp --sport 12345 -A INPUT -p tcp -m tcp --sport 12345 --dport 6789 -A INPUT -p tcp -m tcp --sport 0:1023 -A INPUT -p tcp -m tcp --dport 1024:65535 This would allow to extend iptables-nft to prefer native payload expressions for --sport,dport in the future. Also, parse_cmp must not clear the "payload" flag, this is because cmp-based range expressions will contain following sequence: payload => reg1 cmp reg1 > minv cmp reg1 < maxv ... so second cmp would work. Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++- iptables/nft-shared.h | 3 + 2 files changed, 179 insertions(+), 2 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index d0d0d558..061893cf 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -468,6 +468,170 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->flags |= NFT_XT_CTX_BITWISE; } +static struct xtables_match * +nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name) +{ + struct xtables_match *match; + struct xt_entry_match *m; + unsigned int size; + + match = xtables_find_match(name, XTF_TRY_LOAD, + &cs->matches); + if (!match) + return NULL; + + size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; + m = xtables_calloc(1, size); + m->u.match_size = size; + m->u.user.revision = match->revision; + + strcpy(m->u.user.name, match->name); + match->m = m; + + xs_init_match(match); + + return match; +} + +static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs) +{ + struct xt_tcp *tcp = ctx->tcpudp.tcp; + struct xtables_match *match; + + if (!tcp) { + match = nft_create_match(ctx, cs, "tcp"); + if (!match) + return NULL; + + tcp = (void*)match->m->data; + ctx->tcpudp.tcp = tcp; + } + + return tcp; +} + +static void nft_parse_tcp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + + if (!tcp) + return; + + if (sport >= 0) { + switch (op) { + case NFT_CMP_NEQ: + tcp->invflags |= XT_TCP_INV_SRCPT; + /* fallthrough */ + case NFT_CMP_EQ: + tcp->spts[0] = sport; + tcp->spts[1] = sport; + break; + case NFT_CMP_LT: + tcp->spts[1] = sport > 1 ? sport - 1 : 1; + break; + case NFT_CMP_LTE: + tcp->spts[1] = sport; + break; + case NFT_CMP_GT: + tcp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; + break; + case NFT_CMP_GTE: + tcp->spts[0] = sport; + break; + } + } + + if (dport >= 0) { + switch (op) { + case NFT_CMP_NEQ: + tcp->invflags |= XT_TCP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + tcp->dpts[0] = dport; + tcp->dpts[1] = dport; + break; + case NFT_CMP_LT: + tcp->dpts[1] = dport > 1 ? dport - 1 : 1; + break; + case NFT_CMP_LTE: + tcp->dpts[1] = dport; + break; + case NFT_CMP_GT: + tcp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; + break; + case NFT_CMP_GTE: + tcp->dpts[0] = dport; + break; + } + } +} + +static void nft_parse_th_port(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport, int dport, uint8_t op) +{ + switch (proto) { + case IPPROTO_TCP: + nft_parse_tcp(ctx, cs, sport, dport, op); + break; + } +} + +static void nft_parse_transport(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, void *data) +{ + struct iptables_command_state *cs = data; + uint32_t sdport; + uint16_t port; + uint8_t proto, op; + unsigned int len; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + proto = 0; + break; + } + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + switch(ctx->payload.offset) { + case 0: /* th->sport */ + switch (len) { + case 2: /* load sport only */ + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, port, -1, op); + return; + case 4: /* load both src and dst port */ + sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op); + return; + } + break; + case 2: /* th->dport */ + switch (len) { + case 2: + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, -1, port, op); + return; + } + break; + } +} + static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { void *data = ctx->cs; @@ -483,8 +647,18 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } /* bitwise context is interpreted from payload */ if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - ctx->h->ops->parse_payload(ctx, e, data); - ctx->flags &= ~NFT_XT_CTX_PAYLOAD; + switch (ctx->payload.base) { + case NFT_PAYLOAD_LL_HEADER: + if (ctx->h->family == NFPROTO_BRIDGE) + ctx->h->ops->parse_payload(ctx, e, data); + break; + case NFT_PAYLOAD_NETWORK_HEADER: + ctx->h->ops->parse_payload(ctx, e, data); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport(ctx, e, data); + break; + } } } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index c3241f4b..0a8be709 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -53,6 +53,9 @@ struct nft_xt_ctx { struct nft_handle *h; uint32_t flags; const char *table; + union { + struct xt_tcp *tcp; + } tcpudp; uint32_t reg; struct { -- cgit v1.2.3 From 5795a1b5b611fbf7a64be34b2675f88e8f9bbaef Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:56 +0100 Subject: nft-shared: support native tcp port range delinearize adds support for nft ... tcp dport != min-max Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++- iptables/nft-shared.h | 1 + iptables/nft.c | 1 + 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 061893cf..6989a29f 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -513,6 +513,43 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, return tcp; } +static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + + if (!tcp) + return; + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + tcp->invflags |= XT_TCP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + tcp->spts[0] = sport_from; + tcp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + tcp->invflags |= XT_TCP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + tcp->dpts[0] = dport_from; + tcp->dpts[1] = dport_to; + break; + } + } +} + + static void nft_parse_tcp(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, int sport, int dport, @@ -584,8 +621,22 @@ static void nft_parse_th_port(struct nft_xt_ctx *ctx, } } +static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport_from, int sport_to, + int dport_from, int dport_to, uint8_t op) +{ + switch (proto) { + case IPPROTO_TCP: + nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + } +} + + static void nft_parse_transport(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, void *data) { struct iptables_command_state *cs = data; uint32_t sdport; @@ -632,6 +683,47 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, } } +static void nft_parse_transport_range(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + unsigned int len_from, len_to; + uint8_t proto, op; + uint16_t from, to; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + proto = 0; + break; + } + + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from); + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to); + if (len_to != len_from || len_to != 2) + return; + + op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP); + + from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + + switch(ctx->payload.offset) { + case 0: + nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); + return; + case 2: + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op); + return; + } +} + static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { void *data = ctx->cs; @@ -811,6 +903,25 @@ static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, ctx->h->ops->parse_lookup(ctx, e, NULL); } +static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); + if (reg != ctx->reg) + return; + + if (ctx->flags & NFT_XT_CTX_PAYLOAD) { + switch (ctx->payload.base) { + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport_range(ctx, e, ctx->cs); + break; + default: + break; + } + } +} + void nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) @@ -855,6 +966,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, nft_parse_lookup(&ctx, h, expr); else if (strcmp(name, "log") == 0) nft_parse_log(&ctx, expr); + else if (strcmp(name, "range") == 0) + nft_parse_range(&ctx, expr); expr = nftnl_expr_iter_next(iter); } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0a8be709..1468d560 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -45,6 +45,7 @@ enum { NFT_XT_CTX_BITWISE = (1 << 2), NFT_XT_CTX_IMMEDIATE = (1 << 3), NFT_XT_CTX_PREV_PAYLOAD = (1 << 4), + NFT_XT_CTX_RANGE = (1 << 5), }; struct nft_xt_ctx { diff --git a/iptables/nft.c b/iptables/nft.c index b5de687c..f7f59506 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3529,6 +3529,7 @@ static const char *supported_exprs[] = { "counter", "immediate", "lookup", + "range", }; -- cgit v1.2.3 From 5489493e6590b35765f676d6638c696bfe00c4b4 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:57 +0100 Subject: nft-shared: support native udp port delinearize same as previous patch, but for udp. Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++-- iptables/nft-shared.h | 1 + 2 files changed, 122 insertions(+), 4 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 6989a29f..f7836a01 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -495,6 +495,24 @@ nft_create_match(struct nft_xt_ctx *ctx, return match; } +static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs) +{ + struct xt_udp *udp = ctx->tcpudp.udp; + struct xtables_match *match; + + if (!udp) { + match = nft_create_match(ctx, cs, "udp"); + if (!match) + return NULL; + + udp = (void*)match->m->data; + ctx->tcpudp.udp = udp; + } + + return udp; +} + static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs) { @@ -513,11 +531,47 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, return tcp; } +static void nft_parse_udp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_udp *udp = nft_udp_match(ctx, cs); + + if (!udp) + return; + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + udp->invflags |= XT_UDP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + udp->spts[0] = sport_from; + udp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + udp->invflags |= XT_UDP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + udp->dpts[0] = dport_from; + udp->dpts[1] = dport_to; + break; + } + } +} + static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport_from, int sport_to, - int dport_from, int dport_to, - uint8_t op) + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) { struct xt_tcp *tcp = nft_tcp_match(ctx, cs); @@ -549,6 +603,63 @@ static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, } } +static void nft_parse_udp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_udp *udp = nft_udp_match(ctx, cs); + + if (!udp) + return; + + if (sport >= 0) { + switch (op) { + case NFT_CMP_NEQ: + udp->invflags |= XT_UDP_INV_SRCPT; + /* fallthrough */ + case NFT_CMP_EQ: + udp->spts[0] = sport; + udp->spts[1] = sport; + break; + case NFT_CMP_LT: + udp->spts[1] = sport > 1 ? sport - 1 : 1; + break; + case NFT_CMP_LTE: + udp->spts[1] = sport; + break; + case NFT_CMP_GT: + udp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; + break; + case NFT_CMP_GTE: + udp->spts[0] = sport; + break; + } + } + if (dport >= 0) { + switch (op) { + case NFT_CMP_NEQ: + udp->invflags |= XT_UDP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + udp->dpts[0] = dport; + udp->dpts[1] = dport; + break; + case NFT_CMP_LT: + udp->dpts[1] = dport > 1 ? dport - 1 : 1; + break; + case NFT_CMP_LTE: + udp->dpts[1] = dport; + break; + case NFT_CMP_GT: + udp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; + break; + case NFT_CMP_GTE: + udp->dpts[0] = dport; + break; + } + } +} static void nft_parse_tcp(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, @@ -615,6 +726,9 @@ static void nft_parse_th_port(struct nft_xt_ctx *ctx, int sport, int dport, uint8_t op) { switch (proto) { + case IPPROTO_UDP: + nft_parse_udp(ctx, cs, sport, dport, op); + break; case IPPROTO_TCP: nft_parse_tcp(ctx, cs, sport, dport, op); break; @@ -628,6 +742,9 @@ static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, int dport_from, int dport_to, uint8_t op) { switch (proto) { + case IPPROTO_UDP: + nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; case IPPROTO_TCP: nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); break; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 1468d560..0716c8f4 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -56,6 +56,7 @@ struct nft_xt_ctx { const char *table; union { struct xt_tcp *tcp; + struct xt_udp *udp; } tcpudp; uint32_t reg; -- cgit v1.2.3 From c034cf31dd1a9079e197e4e6bb72bc7d19448114 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:58 +0100 Subject: nft: prefer native expressions instead of udp match Instead of using nft_compat+xtables udp match, prefer to emit payload+cmp or payload+range expression. Delinearization support was added in previous patches. Signed-off-by: Florian Westphal --- iptables/nft.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index f7f59506..9f181de5 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1226,6 +1226,126 @@ static int add_nft_among(struct nft_handle *h, return 0; } +static int expr_gen_range_cmp16(struct nftnl_rule *r, + uint16_t lo, + uint16_t hi, + bool invert) +{ + struct nftnl_expr *e; + + if (lo == hi) { + add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ); + return 0; + } + + if (lo == 0 && hi < 0xffff) { + add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE); + return 0; + } + + e = nftnl_expr_alloc("range"); + if (!e) + return -ENOMEM; + + nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, NFT_REG_1); + nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_OP, invert ? NFT_RANGE_NEQ : NFT_RANGE_EQ); + + lo = htons(lo); + nftnl_expr_set(e, NFTNL_EXPR_RANGE_FROM_DATA, &lo, sizeof(lo)); + hi = htons(hi); + nftnl_expr_set(e, NFTNL_EXPR_RANGE_TO_DATA, &hi, sizeof(hi)); + + nftnl_rule_add_expr(r, e); + return 0; +} + +static int add_nft_tcpudp(struct nftnl_rule *r, + uint16_t src[2], + bool invert_src, + uint16_t dst[2], + bool invert_dst) +{ + struct nftnl_expr *expr; + uint8_t op = NFT_CMP_EQ; + int ret; + + if (src[0] && src[0] == src[1] && + dst[0] && dst[0] == dst[1] && + invert_src == invert_dst) { + uint32_t combined = dst[0] | (src[0] << 16); + + if (invert_src) + op = NFT_CMP_NEQ; + + expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, + NFT_REG_1); + if (!expr) + return -ENOMEM; + + nftnl_rule_add_expr(r, expr); + add_cmp_u32(r, htonl(combined), op); + return 0; + } + + if (src[0] || src[1] < 0xffff) { + expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, + 0, 2, NFT_REG_1); + if (!expr) + return -ENOMEM; + + nftnl_rule_add_expr(r, expr); + ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src); + if (ret) + return ret; + } + + if (dst[0] || dst[1] < 0xffff) { + expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, + 2, 2, NFT_REG_1); + if (!expr) + return -ENOMEM; + + nftnl_rule_add_expr(r, expr); + ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst); + if (ret) + return ret; + } + + return 0; +} + +/* without this, "iptables -A INPUT -m udp" is + * turned into "iptables -A INPUT", which isn't + * compatible with iptables-legacy behaviour. + */ +static bool udp_all_zero(const struct xt_udp *u) +{ + static const struct xt_udp zero = { + .spts[1] = 0xffff, + .dpts[1] = 0xffff, + }; + + return memcmp(u, &zero, sizeof(*u)) == 0; +} + +static int add_nft_udp(struct nftnl_rule *r, struct xt_entry_match *m) +{ + struct xt_udp *udp = (void *)m->data; + + if (udp->invflags > XT_UDP_INV_MASK || + udp_all_zero(udp)) { + struct nftnl_expr *expr = nftnl_expr_alloc("match"); + int ret; + + ret = __add_match(expr, m); + nftnl_rule_add_expr(r, expr); + return ret; + } + + return add_nft_tcpudp(r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT, + udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); +} + int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1236,6 +1356,8 @@ int add_match(struct nft_handle *h, return add_nft_limit(r, m); else if (!strcmp(m->u.user.name, "among")) return add_nft_among(h, r, m); + else if (!strcmp(m->u.user.name, "udp")) + return add_nft_udp(r, m); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From 6aba94ef5f50734dc72f455f195787b9c8540a78 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:59 +0100 Subject: nft: prefer native expressions instead of tcp match Instead of using nft_compat+xtables tcp match, prefer to emit payload+cmp or payload+range expression. Unlike udp, tcp has flag bits that can be matched too but we have to fall back to the xt expression for now. We also don't support tcp option match, but thats a rarely used feature anyway. Delinearization support for ports was added in previous patches. Signed-off-by: Florian Westphal --- iptables/nft.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index 9f181de5..4b5c4332 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1346,6 +1346,36 @@ static int add_nft_udp(struct nftnl_rule *r, struct xt_entry_match *m) udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } +static bool tcp_all_zero(const struct xt_tcp *t) +{ + static const struct xt_tcp zero = { + .spts[1] = 0xffff, + .dpts[1] = 0xffff, + }; + + return memcmp(t, &zero, sizeof(*t)) == 0; +} + +static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) +{ + static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT; + struct xt_tcp *tcp = (void *)m->data; + + if (tcp->invflags & ~supported || tcp->option || + tcp->flg_mask || tcp->flg_cmp || + tcp_all_zero(tcp)) { + struct nftnl_expr *expr = nftnl_expr_alloc("match"); + int ret; + + ret = __add_match(expr, m); + nftnl_rule_add_expr(r, expr); + return ret; + } + + return add_nft_tcpudp(r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT, + tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT); +} + int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1358,6 +1388,8 @@ int add_match(struct nft_handle *h, return add_nft_among(h, r, m); else if (!strcmp(m->u.user.name, "udp")) return add_nft_udp(r, m); + else if (!strcmp(m->u.user.name, "tcp")) + return add_nft_tcp(r, m); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From 92808bd52f04154e01a68c47c2834d2252adf60c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:53:00 +0100 Subject: nft-shared: add tcp flag dissection Detect payload load of th->flags and convert it to xt tcp match structure. Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index f7836a01..746a948c 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -751,6 +751,20 @@ static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, } } +static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t op, uint8_t flags, uint8_t mask) +{ + struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + + if (!tcp) + return; + + if (op == NFT_CMP_NEQ) + tcp->invflags |= XT_TCP_INV_FLAGS; + tcp->flg_cmp = flags; + tcp->flg_mask = mask; +} static void nft_parse_transport(struct nft_xt_ctx *ctx, struct nftnl_expr *e, void *data) @@ -797,6 +811,18 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, return; } break; + case 13: /* th->flags */ + if (len == 1 && proto == IPPROTO_TCP) { + uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + uint8_t mask = ~0; + + if (ctx->flags & NFT_XT_CTX_BITWISE) { + memcpy(&mask, &ctx->bitwise.mask, sizeof(mask)); + ctx->flags &= ~NFT_XT_CTX_BITWISE; + } + nft_parse_tcp_flags(ctx, cs, op, flags, mask); + } + return; } } -- cgit v1.2.3 From 98e69b7e74dc3fc2d7bbd87f8c2cae9559b15df8 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:53:01 +0100 Subject: nft: add support for native tcp flag matching prefer payload + bitwise + cmp to nft_compat match. Signed-off-by: Florian Westphal --- iptables/nft.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 4b5c4332..3e434549 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1346,6 +1346,26 @@ static int add_nft_udp(struct nftnl_rule *r, struct xt_entry_match *m) udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } +static int add_nft_tcpflags(struct nftnl_rule *r, + uint8_t cmp, uint8_t mask, + bool invert) +{ + struct nftnl_expr *e; + + e = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, + 13, 1, NFT_REG_1); + + if (!e) + return -ENOMEM; + + nftnl_rule_add_expr(r, e); + + add_bitwise(r, &mask, 1); + add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ); + + return 0; +} + static bool tcp_all_zero(const struct xt_tcp *t) { static const struct xt_tcp zero = { @@ -1358,11 +1378,10 @@ static bool tcp_all_zero(const struct xt_tcp *t) static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) { - static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT; + static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS; struct xt_tcp *tcp = (void *)m->data; if (tcp->invflags & ~supported || tcp->option || - tcp->flg_mask || tcp->flg_cmp || tcp_all_zero(tcp)) { struct nftnl_expr *expr = nftnl_expr_alloc("match"); int ret; @@ -1372,6 +1391,14 @@ static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) return ret; } + if (tcp->flg_mask) { + int ret = add_nft_tcpflags(r, tcp->flg_cmp, tcp->flg_mask, + tcp->invflags & XT_TCP_INV_FLAGS); + + if (ret < 0) + return ret; + } + return add_nft_tcpudp(r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT, tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT); } -- cgit v1.2.3 From a761a026c60d4ce4e8f9a79b6e51ddc57fe97e1a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Jan 2022 19:35:54 +0100 Subject: nft: Use verbose flag to toggle debug output Copy legacy iptables' behaviour, printing debug output if verbose flag is given more than once. Since nft debug output applies to netlink messages which are not created until nft_action() phase, carrying verbose value is non-trivial - introduce a field in struct nft_handle for that. Signed-off-by: Phil Sutter --- iptables/nft-shared.h | 1 - iptables/nft.c | 38 ++++++++++++++++++++------------------ iptables/nft.h | 1 + iptables/xtables.c | 1 + 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0716c8f4..0788e98a 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -13,7 +13,6 @@ #include "xshared.h" #ifdef DEBUG -#define NLDEBUG #define DEBUG_DEL #endif diff --git a/iptables/nft.c b/iptables/nft.c index 3e434549..7cc6ca52 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -926,15 +926,16 @@ void nft_fini(struct nft_handle *h) mnl_socket_close(h->nl); } -static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh) +static void nft_chain_print_debug(struct nft_handle *h, + struct nftnl_chain *c, struct nlmsghdr *nlh) { -#ifdef NLDEBUG - char tmp[1024]; - - nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0); - printf("DEBUG: chain: %s\n", tmp); - mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); -#endif + if (h->verbose > 1) { + nftnl_chain_fprintf(stdout, c, 0, 0); + fprintf(stdout, "\n"); + } + if (h->verbose > 2) + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct nfgenmsg)); } static struct nftnl_chain *nft_chain_new(struct nft_handle *h, @@ -1567,15 +1568,16 @@ int add_log(struct nftnl_rule *r, struct iptables_command_state *cs) return 0; } -static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh) +static void nft_rule_print_debug(struct nft_handle *h, + struct nftnl_rule *r, struct nlmsghdr *nlh) { -#ifdef NLDEBUG - char tmp[1024]; - - nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0); - printf("DEBUG: rule: %s\n", tmp); - mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); -#endif + if (h->verbose > 1) { + nftnl_rule_fprintf(stdout, r, 0, 0); + fprintf(stdout, "\n"); + } + if (h->verbose > 2) + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct nfgenmsg)); } int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes) @@ -2879,7 +2881,7 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), type, h->family, flags, seq); nftnl_chain_nlmsg_build_payload(nlh, chain); - nft_chain_print_debug(chain, nlh); + nft_chain_print_debug(h, chain, nlh); } static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, @@ -2891,7 +2893,7 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), type, h->family, flags, seq); nftnl_rule_nlmsg_build_payload(nlh, rule); - nft_rule_print_debug(rule, nlh); + nft_rule_print_debug(h, rule, nlh); } static void batch_obj_del(struct nft_handle *h, struct obj_update *o) diff --git a/iptables/nft.h b/iptables/nft.h index 4c78f761..fd116c2e 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -109,6 +109,7 @@ struct nft_handle { int8_t config_done; struct list_head cmd_list; bool cache_init; + int verbose; /* meta data, for error reporting */ struct { diff --git a/iptables/xtables.c b/iptables/xtables.c index 051d5c7b..c44b39ac 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -163,6 +163,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, h->ops->init_cs(&cs); do_parse(argc, argv, &p, &cs, &args); + h->verbose = p.verbose; if (!nft_table_builtin_find(h, p.table)) xtables_error(VERSION_PROBLEM, -- cgit v1.2.3 From 17ed253f9dd401d7b83b81f5db93411bee592a40 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Jan 2022 15:32:10 +0100 Subject: iptables-restore: Support for extra debug output Treat --verbose just like iptables itself, increasing debug level with number of invocations. To propagate the level into do_command() callback, insert virtual '-v' flags into rule lines. The only downside of this is that simple verbose output is changed and now also prints the rules as they are added - which would be useful if the lines contained the chain they apply to. Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 1 + iptables/iptables-restore.c | 6 +++++- .../tests/shell/testcases/ipt-restore/0014-verbose-restore_0 | 9 ++++++--- iptables/xtables-restore.c | 6 +++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index b4b62f92..883da998 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -54,6 +54,7 @@ Only parse and construct the ruleset, but do not commit it. .TP \fB\-v\fP, \fB\-\-verbose\fP Print additional debug info during ruleset processing. +Specify multiple times to increase debug level. .TP \fB\-V\fP, \fB\-\-version\fP Print the program version number. diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index a3efb067..3c0a2389 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -114,7 +114,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, counters = 1; break; case 'v': - verbose = 1; + verbose++; break; case 'V': printf("%s v%s\n", @@ -317,11 +317,15 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, char *pcnt = NULL; char *bcnt = NULL; char *parsestart = buffer; + int i; add_argv(&av_store, argv[0], 0); add_argv(&av_store, "-t", 0); add_argv(&av_store, curtable, 0); + for (i = 0; !noflush && i < verbose; i++) + add_argv(&av_store, "-v", 0); + tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line); if (counters && pcnt && bcnt) { add_argv(&av_store, "--set-counters", 0); diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 index fc8559c5..5daf7a78 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 @@ -33,6 +33,7 @@ Flushing chain \`bar' Flushing chain \`foo' Deleting chain \`bar' Deleting chain \`foo' +ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0 Flushing chain \`PREROUTING' Flushing chain \`INPUT' Flushing chain \`OUTPUT' @@ -41,6 +42,7 @@ Flushing chain \`natbar' Flushing chain \`natfoo' Deleting chain \`natbar' Deleting chain \`natfoo' +ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0 Flushing chain \`PREROUTING' Flushing chain \`OUTPUT' Flushing chain \`rawfoo' @@ -58,9 +60,10 @@ Flushing chain \`OUTPUT' Flushing chain \`secfoo' Deleting chain \`secfoo'" -for ipt in iptables-restore ip6tables-restore; do - diff -u -Z <(echo "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP") -done +EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' -e 's/opt --/opt /' <<< "$EXPECT") + +diff -u -Z <(echo "$EXPECT") <($XT_MULTI iptables-restore -v <<< "$DUMP") +diff -u -Z <(echo "$EXPECT6") <($XT_MULTI ip6tables-restore -v <<< "$DUMP") DUMP="*filter :baz - [0:0] diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 8ca2abff..f5aabf3c 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -206,11 +206,15 @@ static void xtables_restore_parse_line(struct nft_handle *h, char *pcnt = NULL; char *bcnt = NULL; char *parsestart = buffer; + int i; add_argv(&state->av_store, xt_params->program_name, 0); add_argv(&state->av_store, "-t", 0); add_argv(&state->av_store, state->curtable->name, 0); + for (i = 0; !h->noflush && i < verbose; i++) + add_argv(&state->av_store, "-v", 0); + tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line); if (counters && pcnt && bcnt) { add_argv(&state->av_store, "--set-counters", 0); @@ -309,7 +313,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) counters = 1; break; case 'v': - verbose = 1; + verbose++; break; case 'V': printf("%s v%s\n", prog_name, prog_vers); -- cgit v1.2.3 From ad1ed75f203b614fe8f309df8b5021d5e391708a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Feb 2022 10:16:19 +0100 Subject: nft: Set NFTNL_CHAIN_FAMILY in new chains Kernel doesn't need it, but debug output improves significantly. Before this patch: | # iptables-nft -vv -A INPUT | [...] | unknown filter INPUT use 0 type filter hook unknown prio 0 policy accept packets 0 bytes 0 | [...] and after: | # iptables-nft -vv -A INPUT | [...] | ip filter INPUT use 0 type filter hook input prio 0 policy accept packets 0 bytes 0 | [...] While being at it, make nft_chain_builtin_alloc() take only the builtin table's name as parameter - it's the only field it accesses. Signed-off-by: Phil Sutter --- iptables/nft.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 7cc6ca52..301d6c34 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -665,7 +665,7 @@ static int nft_table_builtin_add(struct nft_handle *h, } static struct nftnl_chain * -nft_chain_builtin_alloc(const struct builtin_table *table, +nft_chain_builtin_alloc(int family, const char *tname, const struct builtin_chain *chain, int policy) { struct nftnl_chain *c; @@ -674,7 +674,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table, if (c == NULL) return NULL; - nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name); + nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, family); + nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, tname); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name); nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook); nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio); @@ -693,7 +694,7 @@ static void nft_chain_builtin_add(struct nft_handle *h, { struct nftnl_chain *c; - c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT); + c = nft_chain_builtin_alloc(h->family, table->name, chain, NF_ACCEPT); if (c == NULL) return; @@ -959,7 +960,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, _c = nft_chain_builtin_find(_t, chain); if (_c != NULL) { /* This is a built-in chain */ - c = nft_chain_builtin_alloc(_t, _c, policy); + c = nft_chain_builtin_alloc(h->family, _t->name, _c, policy); if (c == NULL) return NULL; } else { @@ -1999,6 +2000,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl if (c == NULL) return 0; + nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain); if (h->family == NFPROTO_BRIDGE) @@ -2029,6 +2031,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table if (!c) return 0; + nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain); created = true; @@ -2190,6 +2193,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, if (c == NULL) return 0; + nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family); nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname); nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle); -- cgit v1.2.3 From 51d9d9e0813448025271d6948826990eb44b8dcc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Feb 2022 13:27:51 +0100 Subject: ebtables: Support verbose mode Accept '-v' flag in both ebtables-nft and ebtables-nft-restore. Mostly interesting because it allows for netlink debug output when specified multiple times. Signed-off-by: Phil Sutter --- iptables/ebtables-nft.8 | 6 ++++++ iptables/xtables-eb.c | 25 ++++++++++++++++++------- iptables/xtables-restore.c | 8 ++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index 08e9766f..d75aae24 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -307,6 +307,12 @@ of the ebtables kernel table. Replace the current table data by the initial table data. .SS MISCELLANOUS COMMANDS .TP +.B "-v, --verbose" +Verbose mode. +For appending, insertion, deletion and replacement, this causes +detailed information on the rule or rules to be printed. \fB\-v\fP may be +specified multiple times to possibly emit more detailed debug statements. +.TP .B "-V, --version" Show the version of the ebtables userspace program. .TP diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 060e06c5..1e5b50ba 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -195,6 +195,7 @@ struct option ebt_original_options[] = { "out-interface" , required_argument, 0, 'o' }, { "out-if" , required_argument, 0, 'o' }, { "version" , no_argument , 0, 'V' }, + { "verbose" , no_argument , 0, 'v' }, { "help" , no_argument , 0, 'h' }, { "jump" , required_argument, 0, 'j' }, { "set-counters" , required_argument, 0, 'c' }, @@ -219,7 +220,7 @@ struct option ebt_original_options[] = struct xtables_globals ebtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", - .optstring = OPTSTRING_COMMON "h", + .optstring = OPTSTRING_COMMON "hv", .orig_opts = ebt_original_options, .compat_rev = nft_compatible_revision, }; @@ -325,6 +326,7 @@ static void print_help(const struct xtables_target *t, " pcnt bcnt : set the counters of the to be added rule\n" "--modprobe -M program : try to insert modules using this program\n" "--concurrent : use a file lock to support concurrent scripts\n" +"--verbose -v : verbose mode\n" "--version -V : print package version\n\n" "Environment variable:\n" /*ATOMIC_ENV_VARIABLE " : if set (see above) will equal its value"*/ @@ -726,6 +728,9 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, struct ebt_match *match; bool table_set = false; + /* avoid cumulating verbosity with ebtables-restore */ + h->verbose = 0; + /* prevent getopt to spoil our error reporting */ optind = 0; opterr = false; @@ -854,6 +859,10 @@ print_zero: optind++; } break; + case 'v': /* verbose */ + flags |= OPT_VERBOSE; + h->verbose++; + break; case 'V': /* Version */ if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, @@ -1146,24 +1155,26 @@ print_zero: } } else if (command == 'L') { ret = list_rules(h, chain, *table, rule_nr, - 0, + flags & OPT_VERBOSE, 0, /*flags&OPT_EXPANDED*/0, flags&LIST_N, flags&LIST_C); } if (flags & OPT_ZERO) { - ret = nft_cmd_chain_zero_counters(h, chain, *table, 0); + ret = nft_cmd_chain_zero_counters(h, chain, *table, + flags & OPT_VERBOSE); } else if (command == 'F') { - ret = nft_cmd_rule_flush(h, chain, *table, 0); + ret = nft_cmd_rule_flush(h, chain, *table, flags & OPT_VERBOSE); } else if (command == 'A') { - ret = append_entry(h, chain, *table, &cs, 0, 0, true); + ret = append_entry(h, chain, *table, &cs, 0, + flags & OPT_VERBOSE, true); } else if (command == 'I') { ret = append_entry(h, chain, *table, &cs, rule_nr - 1, - 0, false); + flags & OPT_VERBOSE, false); } else if (command == 'D') { ret = delete_entry(h, chain, *table, &cs, rule_nr - 1, - rule_nr_end, 0); + rule_nr_end, flags & OPT_VERBOSE); } /*else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); if (ebt_errormsg[0] != '\0') diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index f5aabf3c..81b25a43 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -417,6 +417,7 @@ static const struct nft_xt_restore_cb ebt_restore_cb = { static const struct option ebt_restore_options[] = { {.name = "noflush", .has_arg = 0, .val = 'n'}, + {.name = "verbose", .has_arg = 0, .val = 'v'}, { 0 } }; @@ -430,15 +431,18 @@ int xtables_eb_restore_main(int argc, char *argv[]) struct nft_handle h; int c; - while ((c = getopt_long(argc, argv, "n", + while ((c = getopt_long(argc, argv, "nv", ebt_restore_options, NULL)) != -1) { switch(c) { case 'n': noflush = 1; break; + case 'v': + verbose++; + break; default: fprintf(stderr, - "Usage: ebtables-restore [ --noflush ]\n"); + "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n"); exit(1); break; } -- cgit v1.2.3 From 73b912920a55dd920effae5f558269ee67947d5f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Feb 2022 13:38:48 +0100 Subject: nft: Add debug output to table creation This at least allows to inspect how tables are created on demand. Also requires setting NFTNL_TABLE_FAMILY for clean output. Signed-off-by: Phil Sutter --- iptables/nft.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index 301d6c34..041e1b8c 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -657,6 +657,7 @@ static int nft_table_builtin_add(struct nft_handle *h, if (t == NULL) return -1; + nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family); nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name); ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1; @@ -2242,6 +2243,7 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist if (t == NULL) return -1; + nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family); nftnl_table_set_str(t, NFTNL_TABLE_NAME, table); obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t); @@ -2832,6 +2834,18 @@ error: return ret; } +static void nft_table_print_debug(struct nft_handle *h, + struct nftnl_table *t, struct nlmsghdr *nlh) +{ + if (h->verbose > 1) { + nftnl_table_fprintf(stdout, t, 0, 0); + fprintf(stdout, "\n"); + } + if (h->verbose > 2) + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct nfgenmsg)); +} + static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, uint16_t flags, uint32_t seq, struct nftnl_table *table) @@ -2841,6 +2855,7 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), type, h->family, flags, seq); nftnl_table_nlmsg_build_payload(nlh, table); + nft_table_print_debug(h, table, nlh); } static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type, -- cgit v1.2.3 From fc8f7289a678d0a4d12383f21415ca8516352705 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Feb 2022 14:44:26 +0100 Subject: nft: cache: Dump rules if debugging If verbose flag was given twice, dump rules while populating the cache. This not only applies to list commands, but all requiring a rule cache - e.g. insert with position. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 43ac291e..608e42a7 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -538,9 +538,15 @@ static int fetch_chain_cache(struct nft_handle *h, return ret; } +struct rule_list_cb_data { + struct nftnl_chain *chain; + int verbose; +}; + static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) { - struct nftnl_chain *c = data; + struct rule_list_cb_data *rld = data; + struct nftnl_chain *c = rld->chain; struct nftnl_rule *r; r = nftnl_rule_alloc(); @@ -552,6 +558,10 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } + if (rld->verbose > 1) { + nftnl_rule_fprintf(stdout, r, 0, 0); + fprintf(stdout, "\n"); + } nftnl_chain_rule_add_tail(r, c); return MNL_CB_OK; } @@ -560,6 +570,10 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) { struct nftnl_chain *c = nc->nftnl; struct nft_handle *h = data; + struct rule_list_cb_data rld = { + .chain = c, + .verbose = h->verbose, + }; char buf[16536]; struct nlmsghdr *nlh; struct nftnl_rule *rule; @@ -581,7 +595,7 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) NLM_F_DUMP, h->seq); nftnl_rule_nlmsg_build_payload(nlh, rule); - ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c); + ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld); if (ret < 0 && errno == EINTR) assert(nft_restart(h) >= 0); -- cgit v1.2.3 From 1407a9c45350839073842bcc8c84ce524db3a119 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Feb 2022 18:45:22 +0100 Subject: tests: iptables-test: Support variant deviation Some test results are not consistent between variants: * CLUSTERIP is not supported with nft_compat, so all related tests fail with iptables-nft. * iptables-legacy mandates TCPMSS be combined with SYN flag match, iptables-nft does not care. (Or precisely, xt_TCPMSS.ko can't validate match presence.) Introduce an optional fourth test spec field to specify the variant it applies to. Consequently, the opposite result is expected with the other variant. Signed-off-by: Phil Sutter --- extensions/libipt_CLUSTERIP.t | 4 ++-- extensions/libxt_TCPMSS.t | 2 +- iptables-test.py | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t index 5af555e0..30b80167 100644 --- a/extensions/libipt_CLUSTERIP.t +++ b/extensions/libipt_CLUSTERIP.t @@ -1,4 +1,4 @@ :INPUT -d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK;LEGACY +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK;LEGACY diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t index 553a3452..fbfbfcf8 100644 --- a/extensions/libxt_TCPMSS.t +++ b/extensions/libxt_TCPMSS.t @@ -1,6 +1,6 @@ :FORWARD,OUTPUT,POSTROUTING *mangle -j TCPMSS;;FAIL --p tcp -j TCPMSS --set-mss 42;;FAIL +-p tcp -j TCPMSS --set-mss 42;;FAIL;LEGACY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK diff --git a/iptables-test.py b/iptables-test.py index 95fa11b1..b49afcab 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -182,6 +182,28 @@ def execute_cmd(cmd, filename, lineno): return ret +def variant_res(res, variant): + ''' + Adjust expected result with given variant + + If expected result is scoped to a variant, the other one yields a different + result. Therefore map @res to itself if given variant is current, invert it + otherwise. + + :param res: expected result from test spec ("OK" or "FAIL") + :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY") + ''' + variant_executable = { + "NFT": "xtables-nft-multi", + "LEGACY": "xtables-legacy-multi" + } + res_inverse = { "OK": "FAIL", "FAIL": "OK" } + + if variant_executable[variant] == EXECUTABLE: + return res + return res_inverse[res] + + def run_test_file(filename, netns): ''' Runs a test file @@ -275,6 +297,9 @@ def run_test_file(filename, netns): rule_save = chain + " " + item[1] res = item[2].rstrip() + if len(item) > 3: + res = variant_res(res, item[3].rstrip()) + ret = run_test(iptables, rule, rule_save, res, filename, lineno + 1, netns) -- cgit v1.2.3 From b7f15b42d82a6b1b493f07b79cebab4c6e09aa9f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 8 Feb 2022 15:06:28 +0100 Subject: iptables.8: Describe the effect of multiple -v flags Functionality differs between legacy and nft variants, detail the effects a bit. Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 759ec54f..ccc498f5 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -360,7 +360,11 @@ byte counters are also listed, with the suffix 'K', 'M' or 'G' for the \fB\-x\fP flag to change this). For appending, insertion, deletion and replacement, this causes detailed information on the rule or rules to be printed. \fB\-v\fP may be -specified multiple times to possibly emit more detailed debug statements. +specified multiple times to possibly emit more detailed debug statements: +Specified twice, \fBiptables-legacy\fP will dump table info and entries in +libiptc, \fBiptables-nft\fP dumps rules in netlink (VM code) presentation. +Specified three times, \fBiptables-nft\fP will also dump any netlink messages +sent to kernel. .TP \fB\-V\fP, \fB\-\-version\fP Show program version and the kernel API used. -- cgit v1.2.3 From 7a006c7d5c58ef93f1606b56d4c9589827c6dc27 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Sat, 12 Feb 2022 16:58:29 +0000 Subject: tests: iptables-test: rename variable "Splitted" hasn't been current since the seventeenth century. Replace it with "tokens". Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables-test.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index b49afcab..91c77e3d 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -107,20 +107,20 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): return -1 matching = 0 - splitted = iptables.split(" ") - if len(splitted) == 2: - if splitted[1] == '-4': + tokens = iptables.split(" ") + if len(tokens) == 2: + if tokens[1] == '-4': command = IPTABLES_SAVE - elif splitted[1] == '-6': + elif tokens[1] == '-6': command = IP6TABLES_SAVE - elif len(splitted) == 1: - if splitted[0] == IPTABLES: + elif len(tokens) == 1: + if tokens[0] == IPTABLES: command = IPTABLES_SAVE - elif splitted[0] == IP6TABLES: + elif tokens[0] == IP6TABLES: command = IP6TABLES_SAVE - elif splitted[0] == ARPTABLES: + elif tokens[0] == ARPTABLES: command = ARPTABLES_SAVE - elif splitted[0] == EBTABLES: + elif tokens[0] == EBTABLES: command = EBTABLES_SAVE command = EXECUTABLE + " " + command @@ -128,7 +128,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if netns: command = "ip netns exec ____iptables-container-test " + command - args = splitted[1:] + args = tokens[1:] proc = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -- cgit v1.2.3 From adb03c3f06ff1f3ac23d3b7b7f10f91122029914 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Sat, 12 Feb 2022 16:58:30 +0000 Subject: tests: add `NOMATCH` test result Currently, there are two supported test results: `OK` and `FAIL`. It is expected that either the iptables command fails, or it succeeds and dumping the rule has the correct output. However, it is possible that the command may succeed but the output may not be correct. Add a `NOMATCH` result to cover this outcome. Make a few white-space improvements at the same time. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables-test.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 91c77e3d..4a587a29 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -73,9 +73,9 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): Executes an unit test. Returns the output of delete_rule(). Parameters: - :param iptables: string with the iptables command to execute + :param iptables: string with the iptables command to execute :param rule: string with iptables arguments for the rule to test - :param rule_save: string to find the rule in the output of iptables -save + :param rule_save: string to find the rule in the output of iptables-save :param res: expected result of the rule. Valid values: "OK", "FAIL" :param filename: name of the file tested (used for print_error purposes) :param lineno: line number being tested (used for print_error purposes) @@ -92,7 +92,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): # report failed test # if ret: - if res == "OK": + if res != "FAIL": reason = "cannot load: " + cmd print_error(reason, filename, lineno) return -1 @@ -146,10 +146,20 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): # find the rule matching = out.find(rule_save.encode('utf-8')) if matching < 0: - reason = "cannot find: " + iptables + " -I " + rule - print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) - return -1 + if res == "OK": + reason = "cannot find: " + iptables + " -I " + rule + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno) + return -1 + else: + # do not report this error + return 0 + else: + if res != "OK": + reason = "should not match: " + cmd + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno) + return -1 # Test "ip netns del NETNS" path with rules in place if netns: @@ -190,14 +200,18 @@ def variant_res(res, variant): result. Therefore map @res to itself if given variant is current, invert it otherwise. - :param res: expected result from test spec ("OK" or "FAIL") + :param res: expected result from test spec ("OK", "FAIL" or "NOMATCH") :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY") ''' variant_executable = { - "NFT": "xtables-nft-multi", - "LEGACY": "xtables-legacy-multi" + "NFT": "xtables-nft-multi", + "LEGACY": "xtables-legacy-multi" + } + res_inverse = { + "OK": "FAIL", + "FAIL": "OK", + "NOMATCH": "OK" } - res_inverse = { "OK": "FAIL", "FAIL": "OK" } if variant_executable[variant] == EXECUTABLE: return res -- cgit v1.2.3 From b8e8ac272efdb0bb42fafe629dbe04c69290c281 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Sat, 12 Feb 2022 16:58:31 +0000 Subject: tests: support explicit variant test result Now that there are more than two test results, add support for explicitly indicating which result to expect if the variants differ. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- iptables-test.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 4a587a29..6acaa822 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -186,22 +186,23 @@ def execute_cmd(cmd, filename, lineno): log_file.flush() # generic check for segfaults - if ret == -11: + if ret == -11: reason = "command segfaults: " + cmd print_error(reason, filename, lineno) return ret -def variant_res(res, variant): +def variant_res(res, variant, alt_res=None): ''' Adjust expected result with given variant If expected result is scoped to a variant, the other one yields a different - result. Therefore map @res to itself if given variant is current, invert it - otherwise. + result. Therefore map @res to itself if given variant is current, use the + alternate result, @alt_res, if specified, invert @res otherwise. :param res: expected result from test spec ("OK", "FAIL" or "NOMATCH") :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY") + :param alt_res: optional expected result for the alternate variant. ''' variant_executable = { "NFT": "xtables-nft-multi", @@ -215,6 +216,8 @@ def variant_res(res, variant): if variant_executable[variant] == EXECUTABLE: return res + if alt_res is not None: + return alt_res return res_inverse[res] @@ -312,7 +315,12 @@ def run_test_file(filename, netns): res = item[2].rstrip() if len(item) > 3: - res = variant_res(res, item[3].rstrip()) + variant = item[3].rstrip() + if len(item) > 4: + alt_res = item[4].rstrip() + else: + alt_res = None + res = variant_res(res, variant, alt_res) ret = run_test(iptables, rule, rule_save, res, filename, lineno + 1, netns) -- cgit v1.2.3 From a3980769541f6deb8d7b185de488dec6f40092f1 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Sat, 12 Feb 2022 16:58:32 +0000 Subject: tests: NFLOG: enable `--nflog-range` tests iptables-legacy and iptable-nft have different results for these tests. Now that it is possible to specify the expected results correctly, we can enable the tests. Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- extensions/libxt_NFLOG.t | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t index 561ec8c7..25f332ae 100644 --- a/extensions/libxt_NFLOG.t +++ b/extensions/libxt_NFLOG.t @@ -3,12 +3,12 @@ -j NFLOG --nflog-group 65535;=;OK -j NFLOG --nflog-group 65536;;FAIL -j NFLOG --nflog-group 0;-j NFLOG;OK -# `--nflog-range` is broken and only supported by xtables-legacy. It -# has been superseded by `--nflog--group`. -# -j NFLOG --nflog-range 1;=;OK -# -j NFLOG --nflog-range 4294967295;=;OK -# -j NFLOG --nflog-range 4294967296;;FAIL -# -j NFLOG --nflog-range -1;;FAIL +# `--nflog-range` is broken and only supported by xtables-legacy. +# It has been superseded by `--nflog--group`. +-j NFLOG --nflog-range 1;=;OK;LEGACY;NOMATCH +-j NFLOG --nflog-range 4294967295;=;OK;LEGACY;NOMATCH +-j NFLOG --nflog-range 4294967296;;FAIL +-j NFLOG --nflog-range -1;;FAIL -j NFLOG --nflog-size 0;=;OK -j NFLOG --nflog-size 1;=;OK -j NFLOG --nflog-size 4294967295;=;OK -- cgit v1.2.3 From 07e2107ef0cbc1b81864c3c0f0ef297a9dfff44d Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 14 Feb 2022 10:35:56 +0100 Subject: xshared: Implement xtables lock timeout using signals Previously, if a lock timeout is specified using `-wN `, flock() is called using LOCK_NB in a loop with a sleep. This results in two issues. The first issue is that the process may wait longer than necessary when the lock becomes available. For this the `-W` option was added, but this requires fine-tuning. The second issue is that if lock contention is high, invocations using `-w` (without a timeout) will always win lock acquisition from invocations that use `-w N`. This is because invocations using `-w` are actively waiting on the lock whereas those using `-w N` only check from time to time whether the lock is free, which will never be the case. This patch removes the sleep loop and deprecates the `-W` option (making it non-functional). Instead, flock() is always called in a blocking fashion, but the alarm() function is used with a non-SA_RESTART signal handler to cancel the system call. Signed-off-by: Jethro Beekman Signed-off-by: Florian Westphal --- iptables/ip6tables.c | 7 +-- iptables/iptables-restore.8.in | 7 --- iptables/iptables-restore.c | 13 ++--- iptables/iptables.8.in | 7 --- iptables/iptables.c | 7 +-- .../shell/testcases/ipt-restore/0002-parameters_0 | 3 +- iptables/xshared.c | 63 +++++++++------------- iptables/xshared.h | 6 +-- 8 files changed, 36 insertions(+), 77 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 560b6ed0..f4796b89 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -712,7 +712,6 @@ int do_command6(int argc, char *argv[], char **table, }; struct xtables_args args = { .family = AF_INET6, - .wait_interval.tv_sec = 1, }; struct ip6t_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; @@ -721,9 +720,6 @@ int do_command6(int argc, char *argv[], char **table, int verbose = 0; int wait = 0; - struct timeval wait_interval = { - .tv_sec = 1, - }; const char *chain = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; @@ -739,7 +735,6 @@ int do_command6(int argc, char *argv[], char **table, newname = p.newname; verbose = p.verbose; wait = args.wait; - wait_interval = args.wait_interval; nsaddrs = args.s.naddrs; ndaddrs = args.d.naddrs; saddrs = args.s.addr.v6; @@ -749,7 +744,7 @@ int do_command6(int argc, char *argv[], char **table, /* Attempt to acquire the xtables lock */ if (!restore) - xtables_lock_or_exit(wait, &wait_interval); + xtables_lock_or_exit(wait); /* only allocate handle if we weren't called with a handle */ if (!*handle) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index 883da998..20216842 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -67,13 +67,6 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP -\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP -Interval to wait per each iteration. -When running latency sensitive applications, waiting for the xtables lock -for extended durations may not be acceptable. This option will make each -iteration take the amount of time specified. The default interval is -1 second. This option only works with \fB\-w\fP. -.TP \fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP Specify the path to the modprobe program. By default, iptables-restore will inspect /proc/sys/kernel/modprobe to determine the executable's path. diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 3c0a2389..1917fb23 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -22,10 +22,6 @@ 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'}, @@ -51,7 +47,6 @@ static void print_usage(const char *name, const char *version) " [ --help ]\n" " [ --noflush ]\n" " [ --wait=\n" - " [ --wait-interval=\n" " [ --table= ]\n" " [ --modprobe= ]\n", name); } @@ -101,6 +96,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, FILE *in; int in_table = 0, testing = 0; const char *tablename = NULL; + bool wait_interval_set = false; line = 0; lock = XT_LOCK_NOT_ACQUIRED; @@ -135,7 +131,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, wait = parse_wait_time(argc, argv); break; case 'W': - parse_wait_interval(argc, argv, &wait_interval); + parse_wait_interval(argc, argv); + wait_interval_set = true; break; case 'M': xtables_modprobe_program = optarg; @@ -165,7 +162,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, } else in = stdin; - if (!wait_interval.tv_sec && !wait) { + if (wait_interval_set && !wait) { fprintf(stderr, "Option --wait-interval requires option --wait\n"); exit(1); } @@ -203,7 +200,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, 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); + lock = xtables_lock_or_exit(wait); /* New table */ char *table; diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index ccc498f5..627ff0e4 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -377,13 +377,6 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP -\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP -Interval to wait per each iteration. -When running latency sensitive applications, waiting for the xtables lock -for extended durations may not be acceptable. This option will make each -iteration take the amount of time specified. The default interval is -1 second. This option only works with \fB\-w\fP. -.TP \fB\-n\fP, \fB\-\-numeric\fP Numeric output. IP addresses and port numbers will be printed in numeric format. diff --git a/iptables/iptables.c b/iptables/iptables.c index f5fe868c..ccebb1a6 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -706,15 +706,11 @@ int do_command4(int argc, char *argv[], char **table, }; struct xtables_args args = { .family = AF_INET, - .wait_interval.tv_sec = 1, }; struct ipt_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *smasks = NULL; struct in_addr *daddrs = NULL, *dmasks = NULL; - struct timeval wait_interval = { - .tv_sec = 1, - }; int verbose = 0; int wait = 0; const char *chain = NULL; @@ -732,7 +728,6 @@ int do_command4(int argc, char *argv[], char **table, newname = p.newname; verbose = p.verbose; wait = args.wait; - wait_interval = args.wait_interval; nsaddrs = args.s.naddrs; ndaddrs = args.d.naddrs; saddrs = args.s.addr.v4; @@ -742,7 +737,7 @@ int do_command4(int argc, char *argv[], char **table, /* Attempt to acquire the xtables lock */ if (!restore) - xtables_lock_or_exit(wait, &wait_interval); + xtables_lock_or_exit(wait); /* only allocate handle if we weren't called with a handle */ if (!*handle) diff --git a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 index 5c8748ec..d632cbc0 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 @@ -2,7 +2,7 @@ set -e -# make sure wait and wait-interval options are accepted +# make sure wait options are accepted clean_tempfile() { @@ -18,4 +18,3 @@ tmpfile=$(mktemp) || exit 1 $XT_MULTI iptables-save -f $tmpfile $XT_MULTI iptables-restore $tmpfile $XT_MULTI iptables-restore -w 5 $tmpfile -$XT_MULTI iptables-restore -w 5 -W 1 $tmpfile diff --git a/iptables/xshared.c b/iptables/xshared.c index 1fd7acc9..50a1d48a 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -13,11 +13,11 @@ #include #include #include -#include #include #include #include #include +#include #include "xshared.h" /* @@ -243,14 +243,14 @@ void xs_init_match(struct xtables_match *match) match->init(match->m); } -static int xtables_lock(int wait, struct timeval *wait_interval) +static void alarm_ignore(int i) { +} + +static int xtables_lock(int wait) { - struct timeval time_left, wait_time; + struct sigaction sigact_alarm; const char *lock_file; - int fd, i = 0; - - time_left.tv_sec = wait; - time_left.tv_usec = 0; + int fd; lock_file = getenv("XTABLES_LOCKFILE"); if (lock_file == NULL || lock_file[0] == '\0') @@ -263,31 +263,24 @@ static int xtables_lock(int wait, struct timeval *wait_interval) return XT_LOCK_FAILED; } - if (wait == -1) { - if (flock(fd, LOCK_EX) == 0) - return fd; - - fprintf(stderr, "Can't lock %s: %s\n", lock_file, - strerror(errno)); - return XT_LOCK_BUSY; + if (wait != -1) { + sigact_alarm.sa_handler = alarm_ignore; + sigact_alarm.sa_flags = SA_RESETHAND; + sigemptyset(&sigact_alarm.sa_mask); + sigaction(SIGALRM, &sigact_alarm, NULL); + alarm(wait); } - while (1) { - if (flock(fd, LOCK_EX | LOCK_NB) == 0) - return fd; - else if (timercmp(&time_left, wait_interval, <)) - return XT_LOCK_BUSY; + if (flock(fd, LOCK_EX) == 0) + return fd; - if (++i % 10 == 0) { - fprintf(stderr, "Another app is currently holding the xtables lock; " - "still %lds %ldus time ahead to have a chance to grab the lock...\n", - time_left.tv_sec, time_left.tv_usec); - } - - wait_time = *wait_interval; - select(0, NULL, NULL, NULL, &wait_time); - timersub(&time_left, wait_interval, &time_left); + if (errno == EINTR) { + errno = EWOULDBLOCK; } + + fprintf(stderr, "Can't lock %s: %s\n", lock_file, + strerror(errno)); + return XT_LOCK_BUSY; } void xtables_unlock(int lock) @@ -296,9 +289,9 @@ void xtables_unlock(int lock) close(lock); } -int xtables_lock_or_exit(int wait, struct timeval *wait_interval) +int xtables_lock_or_exit(int wait) { - int lock = xtables_lock(wait, wait_interval); + int lock = xtables_lock(wait); if (lock == XT_LOCK_FAILED) { xtables_free_opts(1); @@ -334,7 +327,7 @@ int parse_wait_time(int argc, char *argv[]) return wait; } -void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval) +void parse_wait_interval(int argc, char *argv[]) { const char *arg; unsigned int usec; @@ -354,8 +347,7 @@ void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval) "too long usec wait %u > 999999 usec", usec); - wait_interval->tv_sec = 0; - wait_interval->tv_usec = usec; + fprintf(stderr, "Ignoring deprecated --wait-interval option.\n"); return; } xtables_error(PARAMETER_PROBLEM, "wait interval not numeric"); @@ -1235,9 +1227,6 @@ xtables_printhelp(const struct xtables_rule_match *matches) " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" " --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" interval to wait for xtables lock\n" -" default is 1 second\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n"); @@ -1665,7 +1654,7 @@ void do_parse(int argc, char *argv[], "iptables-restore"); } - parse_wait_interval(argc, argv, &args->wait_interval); + parse_wait_interval(argc, argv); wait_interval_set = true; break; diff --git a/iptables/xshared.h b/iptables/xshared.h index d13de95e..0de0e12e 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -189,10 +188,10 @@ enum { XT_LOCK_NOT_ACQUIRED = -3, }; extern void xtables_unlock(int lock); -extern int xtables_lock_or_exit(int wait, struct timeval *tv); +extern int xtables_lock_or_exit(int wait); int parse_wait_time(int argc, char *argv[]); -void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval); +void parse_wait_interval(int argc, char *argv[]); int parse_counters(const char *string, struct xt_counters *ctr); bool tokenize_rule_counters(char **bufferp, char **pcnt, char **bcnt, int line); bool xs_has_arg(int argc, char *argv[]); @@ -294,7 +293,6 @@ struct xtables_args { const char *arp_htype, *arp_ptype; unsigned long long pcnt_cnt, bcnt_cnt; int wait; - struct timeval wait_interval; }; struct xt_cmd_parse_ops { -- cgit v1.2.3 From 2dbb49d15fb44ddd521a734eca3be3f940b7c1ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 11 Feb 2022 17:39:24 +0100 Subject: libxtables: Register only the highest revision extension When fully registering extensions, ignore all consecutive ones with same name and family value. Since commit b3ac87038f4e4 ("libxtables: Make sure extensions register in revision order"), one may safely assume the list of pending extensions has highest revision numbers first. Since iptables is only interested in the highest revision the kernel supports, registration and compatibility checks may be skipped once the first matching extension in pending list has validated. Signed-off-by: Phil Sutter --- libxtables/xtables.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 50fd6a44..b34d62ac 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -697,6 +697,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, struct xtables_match **dptr; struct xtables_match *ptr; const char *icmp6 = "icmp6"; + bool found = false; if (strlen(name) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -715,7 +716,9 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; - if (xtables_fully_register_pending_match(ptr, prev)) { + if (!found && + xtables_fully_register_pending_match(ptr, prev)) { + found = true; prev = ptr; continue; } else if (prev) { @@ -817,6 +820,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) struct xtables_target *prev = NULL; struct xtables_target **dptr; struct xtables_target *ptr; + bool found = false; /* Standard target? */ if (strcmp(name, "") == 0 @@ -831,7 +835,9 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; - if (xtables_fully_register_pending_target(ptr, prev)) { + if (!found && + xtables_fully_register_pending_target(ptr, prev)) { + found = true; prev = ptr; continue; } else if (prev) { -- cgit v1.2.3 From 17534cb18ed0a5052dc45c117401251359dba6aa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 11 Feb 2022 17:47:22 +0100 Subject: Improve error messages for unsupported extensions If a given extension was not supported by the kernel, iptables would print a rather confusing error message if extension parameters were given: | # rm /lib/modules/$(uname -r)/kernel/net/netfilter/xt_LOG.ko | # iptables -A FORWARD -j LOG --log-prefix foo | iptables v1.8.7 (legacy): unknown option "--log-prefix" Avoid this by pretending extension revision 0 is always supported. It is the same hack as used to successfully print extension help texts as unprivileged user, extended to all error codes to serve privileged ones as well. In addition, print a warning if kernel rejected revision 0 and it's not a permissions problem. This helps users find out which extension in a rule the kernel didn't like. Finally, the above commands result in these messages: | Warning: Extension LOG revision 0 not supported, missing kernel module? | iptables: No chain/target/match by that name. Or, for iptables-nft: | Warning: Extension LOG revision 0 not supported, missing kernel module? | iptables v1.8.7 (nf_tables): RULE_APPEND failed (No such file or directory): rule in chain FORWARD Signed-off-by: Phil Sutter --- iptables/nft.c | 12 +++++++++--- libxtables/xtables.c | 7 ++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 041e1b8c..d011d7c8 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3514,10 +3514,16 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt) err: mnl_socket_close(nl); - /* pretend revision 0 is valid if not permitted to check - - * this is required for printing extension help texts as user */ - if (ret < 0 && errno == EPERM && rev == 0) + /* pretend revision 0 is valid - + * this is required for printing extension help texts as user, also + * helps error messaging on unavailable kernel extension */ + if (ret < 0 && rev == 0) { + if (errno != EPERM) + fprintf(stderr, + "Warning: Extension %s revision 0 not supported, missing kernel module?\n", + name); return 1; + } return ret < 0 ? 0 : 1; } diff --git a/libxtables/xtables.c b/libxtables/xtables.c index b34d62ac..87424d04 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -958,7 +958,12 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt) /* Definitely don't support this? */ if (errno == ENOENT || errno == EPROTONOSUPPORT) { close(sockfd); - return 0; + /* Pretend revision 0 support for better error messaging */ + if (revision == 0) + fprintf(stderr, + "Warning: Extension %s revision 0 not supported, missing kernel module?\n", + name); + return (revision == 0); } else if (errno == ENOPROTOOPT) { close(sockfd); /* Assume only revision 0 support (old kernel) */ -- cgit v1.2.3 From b5f2faea325a315bfb932ebc634f3298d4824cae Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Mar 2022 18:59:31 +0100 Subject: nft: Simplify immediate parsing Implementations of parse_immediate callback are mostly trivial, the only relevant part is access to family-specific parts of struct iptables_command_state when setting goto flag for iptables and ip6tables. Refactor them into simple set_goto_flag callbacks. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- iptables/nft-arp.c | 9 --------- iptables/nft-bridge.c | 9 --------- iptables/nft-ipv4.c | 12 +++--------- iptables/nft-ipv6.c | 12 +++--------- iptables/nft-shared.c | 17 +++++++---------- iptables/nft-shared.h | 2 +- 6 files changed, 14 insertions(+), 47 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 1472b115..78509ce9 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -182,14 +182,6 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, fw->arp.invflags |= flags; } -static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; -} - static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) { mask->s_addr = ctx->bitwise.mask[0]; @@ -797,7 +789,6 @@ struct nft_family_ops nft_family_ops_arp = { .print_payload = NULL, .parse_meta = nft_arp_parse_meta, .parse_payload = nft_arp_parse_payload, - .parse_immediate = nft_arp_parse_immediate, .print_header = nft_arp_print_header, .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 90d55e44..d6a0d6e5 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -251,14 +251,6 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, } } -static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; -} - /* return 0 if saddr, 1 if daddr, -1 on error */ static int lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len) @@ -891,7 +883,6 @@ struct nft_family_ops nft_family_ops_bridge = { .print_payload = NULL, .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, - .parse_immediate = nft_bridge_parse_immediate, .parse_lookup = nft_bridge_parse_lookup, .parse_match = nft_bridge_parse_match, .parse_target = nft_bridge_parse_target, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index f374d468..bdb105f8 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -215,15 +215,9 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, } } -static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto, - void *data) +static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; - - if (nft_goto) - cs->fw.ip.flags |= IPT_F_GOTO; + cs->fw.ip.flags |= IPT_F_GOTO; } static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, @@ -450,7 +444,7 @@ struct nft_family_ops nft_family_ops_ipv4 = { .is_same = nft_ipv4_is_same, .parse_meta = nft_ipv4_parse_meta, .parse_payload = nft_ipv4_parse_payload, - .parse_immediate = nft_ipv4_parse_immediate, + .set_goto_flag = nft_ipv4_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv4_print_rule, .save_rule = nft_ipv4_save_rule, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 9ecc754f..a5323171 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -180,15 +180,9 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, } } -static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto, - void *data) +static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; - - if (nft_goto) - cs->fw6.ipv6.flags |= IP6T_F_GOTO; + cs->fw6.ipv6.flags |= IP6T_F_GOTO; } static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, @@ -418,7 +412,7 @@ struct nft_family_ops nft_family_ops_ipv6 = { .is_same = nft_ipv6_is_same, .parse_meta = nft_ipv6_parse_meta, .parse_payload = nft_ipv6_parse_payload, - .parse_immediate = nft_ipv6_parse_immediate, + .set_goto_flag = nft_ipv6_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv6_print_rule, .save_rule = nft_ipv6_save_rule, diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 746a948c..daa251ae 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -906,9 +906,7 @@ static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters 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); - const char *jumpto = NULL; - bool nft_goto = false; - void *data = ctx->cs; + struct iptables_command_state *cs = ctx->cs; int verdict; if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { @@ -931,23 +929,22 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) /* Standard target? */ switch(verdict) { case NF_ACCEPT: - jumpto = "ACCEPT"; + cs->jumpto = "ACCEPT"; break; case NF_DROP: - jumpto = "DROP"; + cs->jumpto = "DROP"; break; case NFT_RETURN: - jumpto = "RETURN"; + cs->jumpto = "RETURN"; break;; case NFT_GOTO: - nft_goto = true; + if (ctx->h->ops->set_goto_flag) + ctx->h->ops->set_goto_flag(cs); /* fall through */ case NFT_JUMP: - jumpto = chain; + cs->jumpto = chain; break; } - - ctx->h->ops->parse_immediate(jumpto, nft_goto, data); } static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0788e98a..04b1d97f 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -93,7 +93,7 @@ struct nft_family_ops { void *data); void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, void *data); - void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data); + void (*set_goto_flag)(struct iptables_command_state *cs); void (*print_table_header)(const char *tablename); void (*print_header)(unsigned int format, const char *chain, -- cgit v1.2.3 From 07ee529f5a62838d68be59683be99bf6a7cda0f2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Mar 2022 19:46:21 +0100 Subject: nft: Speed up immediate parsing Parsing of rules which jump to a chain pointlessly causes a call to xtables_find_target() despite the code already knowing the outcome. Avoid the significant delay for rulesets with many chain jumps by performing the (standard) target lookup only for accept/drop/return verdicts. From a biased test-case on my VM: | # iptables-nft-save | grep -c -- '-j' | 133943 | # time ./old/iptables-nft-save >/dev/null | real 0m45.566s | user 0m1.308s | sys 0m8.430s | # time ./new/iptables-nft-save >/dev/null | real 0m3.547s | user 0m0.762s | sys 0m2.476s Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- iptables/nft-bridge.c | 1 + iptables/nft-shared.c | 37 ++++++++++++++++++------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index d6a0d6e5..d342858e 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -502,6 +502,7 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data) } cs->target = t; + cs->jumpto = t->name; } static void nft_rule_to_ebtables_command_state(struct nft_handle *h, diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index daa251ae..861aa064 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -907,6 +907,8 @@ 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 iptables_command_state *cs = ctx->cs; + struct xt_entry_target *t; + uint32_t size; int verdict; if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { @@ -943,8 +945,21 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) /* fall through */ case NFT_JUMP: cs->jumpto = chain; - break; + /* fall through */ + default: + return; } + + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + 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; } static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -1143,25 +1158,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, } } - if (cs->target != NULL) { - cs->jumpto = cs->target->name; - } else if (cs->jumpto != NULL) { - struct xt_entry_target *t; - uint32_t size; - - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - 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 { + if (!cs->jumpto) cs->jumpto = ""; - } } void nft_clear_iptables_command_state(struct iptables_command_state *cs) @@ -1326,6 +1324,7 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data) struct iptables_command_state *cs = data; cs->target = t; + cs->jumpto = t->name; } void nft_check_xt_legacy(int family, bool is_ipt_save) -- cgit v1.2.3 From b6196c7504d4d41827cea86c167926125cdbf1f3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Mar 2022 23:05:29 +0100 Subject: xshared: Prefer xtables_chain_protos lookup over getprotoent When dumping a large ruleset, common protocol matches such as for TCP port number significantly slow down rule printing due to repeated calls for getprotobynumber(). The latter does not involve any caching, so /etc/protocols is consulted over and over again. As a simple countermeasure, make functions converting between proto number and name prefer the built-in list of "well-known" protocols. This is not a perfect solution, repeated rules for protocol names libxtables does not cache (e.g. igmp or dccp) will still be slow. Implementing getprotoent() result caching could solve this. As a side-effect, explicit check for pseudo-protocol "all" may be dropped as it is contained in the built-in list and therefore immutable. Also update xtables_chain_protos entries a bit to align with typical /etc/protocols contents. The testsuite assumes those names, so the preferred ones prior to this patch are indeed uncommon nowadays. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- iptables/xshared.c | 8 ++++---- libxtables/xtables.c | 19 ++++++------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 50a1d48a..43321d3b 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -53,16 +53,16 @@ proto_to_name(uint16_t proto, int nolookup) { unsigned int i; + for (i = 0; xtables_chain_protos[i].name != NULL; ++i) + if (xtables_chain_protos[i].num == proto) + return xtables_chain_protos[i].name; + if (proto && !nolookup) { struct protoent *pent = getprotobynumber(proto); if (pent) return pent->p_name; } - for (i = 0; xtables_chain_protos[i].name != NULL; ++i) - if (xtables_chain_protos[i].num == proto) - return xtables_chain_protos[i].name; - return NULL; } diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 87424d04..094cbd87 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -2101,10 +2101,11 @@ const struct xtables_pprot xtables_chain_protos[] = { {"udp", IPPROTO_UDP}, {"udplite", IPPROTO_UDPLITE}, {"icmp", IPPROTO_ICMP}, - {"icmpv6", IPPROTO_ICMPV6}, {"ipv6-icmp", IPPROTO_ICMPV6}, + {"icmpv6", IPPROTO_ICMPV6}, {"esp", IPPROTO_ESP}, {"ah", IPPROTO_AH}, + {"mobility-header", IPPROTO_MH}, {"ipv6-mh", IPPROTO_MH}, {"mh", IPPROTO_MH}, {"all", 0}, @@ -2120,23 +2121,15 @@ xtables_parse_protocol(const char *s) if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) return proto; - /* first deal with the special case of 'all' to prevent - * people from being able to redefine 'all' in nsswitch - * and/or provoke expensive [not working] ldap/nis/... - * lookups */ - if (strcmp(s, "all") == 0) - return 0; + for (i = 0; xtables_chain_protos[i].name != NULL; ++i) { + if (strcmp(s, xtables_chain_protos[i].name) == 0) + return xtables_chain_protos[i].num; + } pent = getprotobyname(s); if (pent != NULL) return pent->p_proto; - for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) { - if (xtables_chain_protos[i].name == NULL) - continue; - if (strcmp(s, xtables_chain_protos[i].name) == 0) - return xtables_chain_protos[i].num; - } xt_params->exit_err(PARAMETER_PROBLEM, "unknown protocol \"%s\" specified", s); return -1; -- cgit v1.2.3 From 0c0cd4340ed88fdd2e80d2d5ffc5886c41f5dee0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Mar 2022 23:19:59 +0100 Subject: nft: Don't pass command state opaque to family ops callbacks There are no family-specific versions of struct iptables_command_state anymore, so no need to hide it behind void pointer. Pass the type as-is and save a few casts. While at it, drop unused callbacks parse_bitwise and parse_cmp. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- iptables/nft-arp.c | 23 ++++++++++------------- iptables/nft-bridge.c | 45 ++++++++++++++++++++++----------------------- iptables/nft-ipv4.c | 28 +++++++++++----------------- iptables/nft-ipv6.c | 28 +++++++++++----------------- iptables/nft-shared.c | 23 ++++++++++------------- iptables/nft-shared.h | 33 +++++++++++++++++---------------- iptables/nft.c | 4 ++-- iptables/nft.h | 2 +- 8 files changed, 84 insertions(+), 102 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 78509ce9..028b06a6 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -54,9 +54,9 @@ static bool need_devaddr(struct arpt_devaddr_info *info) return false; } -static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) +static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; uint32_t op; int ret = 0; @@ -169,9 +169,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) } static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data) + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; uint8_t flags = 0; @@ -213,9 +212,9 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, } static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; struct in_addr addr; uint16_t ar_hrd, ar_pro, ar_op; @@ -464,10 +463,8 @@ after_devdst: } static void -nft_arp_save_rule(const void *data, unsigned int format) +nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format) { - const struct iptables_command_state *cs = data; - format |= FMT_NUMERIC; printf(" "); @@ -504,11 +501,11 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_clear_iptables_command_state(&cs); } -static bool nft_arp_is_same(const void *data_a, - const void *data_b) +static bool nft_arp_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct arpt_entry *a = data_a; - const struct arpt_entry *b = data_b; + const struct arpt_entry *a = &cs_a->arp; + const struct arpt_entry *b = &cs_b->arp; if (a->arp.src.s_addr != b->arp.src.s_addr || a->arp.tgt.s_addr != b->arp.tgt.s_addr diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index d342858e..d4b66a25 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -97,9 +97,9 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) } static int nft_bridge_add(struct nft_handle *h, - struct nftnl_rule *r, void *data) + struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_match *iter; struct ebt_entry *fw = &cs->eb; uint32_t op; @@ -164,9 +164,9 @@ static int nft_bridge_add(struct nft_handle *h, } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_entry *fw = &cs->eb; uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; @@ -200,9 +200,9 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, } static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_entry *fw = &cs->eb; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; @@ -397,7 +397,7 @@ static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, } static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e) { struct xtables_match *match = NULL; struct nft_among_data *among_data; @@ -483,17 +483,15 @@ static void parse_watcher(void *object, struct ebt_match **match_list, (*match_list)->next = m; } -static void nft_bridge_parse_match(struct xtables_match *m, void *data) +static void nft_bridge_parse_match(struct xtables_match *m, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - parse_watcher(m, &cs->match_list, true); } -static void nft_bridge_parse_target(struct xtables_target *t, void *data) +static void nft_bridge_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - /* harcoded names :-( */ if (strcmp(t->name, "log") == 0 || strcmp(t->name, "nflog") == 0) { @@ -594,10 +592,9 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("%s ", ent->e_name); } -static void __nft_bridge_save_rule(const void *data, unsigned int format) +static void __nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) { - const struct iptables_command_state *cs = data; - if (cs->eb.ethproto) print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO, cs->eb.bitmask); @@ -645,10 +642,11 @@ static void __nft_bridge_save_rule(const void *data, unsigned int format) fputc('\n', stdout); } -static void nft_bridge_save_rule(const void *data, unsigned int format) +static void nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) { printf(" "); - __nft_bridge_save_rule(data, format); + __nft_bridge_save_rule(cs, format); } static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, @@ -672,10 +670,11 @@ static void nft_bridge_save_chain(const struct nftnl_chain *c, printf(":%s %s\n", chain, policy ?: "ACCEPT"); } -static bool nft_bridge_is_same(const void *data_a, const void *data_b) +static bool nft_bridge_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct ebt_entry *a = data_a; - const struct ebt_entry *b = data_b; + const struct ebt_entry *a = &cs_a->eb; + const struct ebt_entry *b = &cs_b->eb; int i; if (a->ethproto != b->ethproto || @@ -821,9 +820,9 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv xt_xlate_add(xl, " "); } -static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) +static int nft_bridge_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) { - const struct iptables_command_state *cs = data; int ret; xlate_ifname(xl, "iifname", cs->eb.in, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index bdb105f8..af3d0c98 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -26,9 +26,9 @@ #include "nft.h" #include "nft-shared.h" -static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data) +static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct xtables_rule_match *matchp; uint32_t op; int ret; @@ -93,12 +93,9 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data) return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO)); } -static bool nft_ipv4_is_same(const void *data_a, - const void *data_b) +static bool nft_ipv4_is_same(const struct iptables_command_state *a, + const struct iptables_command_state *b) { - const struct iptables_command_state *a = data_a; - const struct iptables_command_state *b = data_b; - if (a->fw.ip.src.s_addr != b->fw.ip.src.s_addr || a->fw.ip.dst.s_addr != b->fw.ip.dst.s_addr || a->fw.ip.smsk.s_addr != b->fw.ip.smsk.s_addr @@ -135,10 +132,8 @@ static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) } static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data) + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - switch (ctx->meta.key) { case NFT_META_L4PROTO: cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); @@ -160,9 +155,9 @@ static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) } static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct in_addr addr; uint8_t proto; bool inv; @@ -250,10 +245,9 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_clear_iptables_command_state(&cs); } -static void nft_ipv4_save_rule(const void *data, unsigned int format) +static void nft_ipv4_save_rule(const struct iptables_command_state *cs, + unsigned int format) { - const struct iptables_command_state *cs = data; - save_ipv4_addr('s', &cs->fw.ip.src, &cs->fw.ip.smsk, cs->fw.ip.invflags & IPT_INV_SRCIP); save_ipv4_addr('d', &cs->fw.ip.dst, &cs->fw.ip.dmsk, @@ -296,9 +290,9 @@ static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr, } } -static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl) +static int nft_ipv4_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) { - const struct iptables_command_state *cs = data; const char *comment; int ret; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index a5323171..892a4854 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -25,9 +25,9 @@ #include "nft.h" #include "nft-shared.h" -static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data) +static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct xtables_rule_match *matchp; uint32_t op; int ret; @@ -82,12 +82,9 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data) return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO)); } -static bool nft_ipv6_is_same(const void *data_a, - const void *data_b) +static bool nft_ipv6_is_same(const struct iptables_command_state *a, + const struct iptables_command_state *b) { - const struct iptables_command_state *a = data_a; - const struct iptables_command_state *b = data_b; - if (memcmp(a->fw6.ipv6.src.s6_addr, b->fw6.ipv6.src.s6_addr, sizeof(struct in6_addr)) != 0 || memcmp(a->fw6.ipv6.dst.s6_addr, b->fw6.ipv6.dst.s6_addr, @@ -108,10 +105,8 @@ static bool nft_ipv6_is_same(const void *data_a, } static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data) + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - switch (ctx->meta.key) { case NFT_META_L4PROTO: cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); @@ -133,9 +128,9 @@ static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask) } static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct in6_addr addr; uint8_t proto; bool inv; @@ -213,10 +208,9 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, nft_clear_iptables_command_state(&cs); } -static void nft_ipv6_save_rule(const void *data, unsigned int format) +static void nft_ipv6_save_rule(const struct iptables_command_state *cs, + unsigned int format) { - const struct iptables_command_state *cs = data; - save_ipv6_addr('s', &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, cs->fw6.ipv6.invflags & IP6T_INV_SRCIP); save_ipv6_addr('d', &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, @@ -257,9 +251,9 @@ static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr, } } -static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl) +static int nft_ipv6_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) { - const struct iptables_command_state *cs = data; const char *comment; int ret; diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 861aa064..c5721854 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -319,7 +319,6 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct xtables_target *target; struct xt_entry_target *t; size_t size; - void *data = ctx->cs; target = xtables_find_target(targname, XTF_TRY_LOAD); if (target == NULL) @@ -335,7 +334,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) target->t = t; - ctx->h->ops->parse_target(target, data); + ctx->h->ops->parse_target(target, ctx->cs); } static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -767,9 +766,9 @@ static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, } static void nft_parse_transport(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; uint32_t sdport; uint16_t port; uint8_t proto, op; @@ -869,7 +868,6 @@ static void nft_parse_transport_range(struct nft_xt_ctx *ctx, static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { - void *data = ctx->cs; uint32_t reg; reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); @@ -877,7 +875,7 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) return; if (ctx->flags & NFT_XT_CTX_META) { - ctx->h->ops->parse_meta(ctx, e, data); + ctx->h->ops->parse_meta(ctx, e, ctx->cs); ctx->flags &= ~NFT_XT_CTX_META; } /* bitwise context is interpreted from payload */ @@ -885,13 +883,13 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) switch (ctx->payload.base) { case NFT_PAYLOAD_LL_HEADER: if (ctx->h->family == NFPROTO_BRIDGE) - ctx->h->ops->parse_payload(ctx, e, data); + ctx->h->ops->parse_payload(ctx, e, ctx->cs); break; case NFT_PAYLOAD_NETWORK_HEADER: - ctx->h->ops->parse_payload(ctx, e, data); + ctx->h->ops->parse_payload(ctx, e, ctx->cs); break; case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport(ctx, e, data); + nft_parse_transport(ctx, e, ctx->cs); break; } } @@ -1055,7 +1053,7 @@ static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, struct nftnl_expr *e) { if (ctx->h->ops->parse_lookup) - ctx->h->ops->parse_lookup(ctx, e, NULL); + ctx->h->ops->parse_lookup(ctx, e); } static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -1319,10 +1317,9 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2) return true; } -void nft_ipv46_parse_target(struct xtables_target *t, void *data) +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - cs->target = t; cs->jumpto = t->name; } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 04b1d97f..7b337943 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -78,21 +78,17 @@ struct nft_xt_ctx { }; struct nft_family_ops { - int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data); - bool (*is_same)(const void *data_a, - const void *data_b); + int (*add)(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs); + bool (*is_same)(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b); void (*print_payload)(struct nftnl_expr *e, struct nftnl_expr_iter *iter); void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data); + struct iptables_command_state *cs); void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data); - void (*parse_bitwise)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data); - void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data); - void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data); + struct iptables_command_state *cs); + void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); void (*set_goto_flag)(struct iptables_command_state *cs); void (*print_table_header)(const char *tablename); @@ -102,16 +98,20 @@ struct nft_family_ops { int refs, uint32_t entries); void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format); - void (*save_rule)(const void *data, unsigned int format); + void (*save_rule)(const struct iptables_command_state *cs, + unsigned int format); void (*save_chain)(const struct nftnl_chain *c, const char *policy); struct xt_cmd_parse_ops cmd_parse; - void (*parse_match)(struct xtables_match *m, void *data); - void (*parse_target)(struct xtables_target *t, void *data); + void (*parse_match)(struct xtables_match *m, + struct iptables_command_state *cs); + void (*parse_target)(struct xtables_target *t, + struct iptables_command_state *cs); void (*init_cs)(struct iptables_command_state *cs); void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); - int (*xlate)(const void *data, struct xt_xlate *xl); + int (*xlate)(const struct iptables_command_state *cs, + struct xt_xlate *xl); int (*add_entry)(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cs, @@ -173,7 +173,8 @@ void save_matches_and_target(const struct iptables_command_state *cs, struct nft_family_ops *nft_family_ops_lookup(int family); -void nft_ipv46_parse_target(struct xtables_target *t, void *data); +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs); bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); diff --git a/iptables/nft.c b/iptables/nft.c index d011d7c8..6883662f 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1648,7 +1648,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv) struct nftnl_rule * nft_rule_new(struct nft_handle *h, const char *chain, const char *table, - void *data) + struct iptables_command_state *cs) { struct nftnl_rule *r; @@ -1660,7 +1660,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table, nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table); nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain); - if (h->ops->add(h, r, data) < 0) + if (h->ops->add(h, r, cs) < 0) goto err; return r; diff --git a/iptables/nft.h b/iptables/nft.h index fd116c2e..68b0910c 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -173,7 +173,7 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h, */ struct nftnl_rule; -struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data); +struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cs); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose); int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose); int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose); -- cgit v1.2.3 From 0c8e253595bd80e4ddd73230d079e33cd5420b32 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Mar 2022 12:17:25 +0100 Subject: libxtables: Fix for warning in xtables_ipmask_to_numeric Gcc complains: | xtables.c: In function 'xtables_ipmask_to_numeric': | xtables.c:1491:34: warning: '__builtin___sprintf_chk' may write a terminating nul past the end of the destination [-Wformat-overflow=] | 1491 | sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask)); | | ^ Indeed, xtables_ipaddr_to_numeric() returns a pointer to a 20 byte buffer and xtables_ipmask_to_numeric() writes its content into a buffer of same size at offset 1. Yet length of returned string is deterministic as it is an IPv4 address. So shrink it to the minimum of 16 bytes which eliminates the warning as well. Fixes: a96166c24eaac ("libxtables: add xtables_ip[6]mask_to_cidr") Signed-off-by: Phil Sutter --- libxtables/xtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 094cbd87..5f47f627 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -1418,7 +1418,7 @@ void xtables_param_act(unsigned int status, const char *p1, ...) const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp) { - static char buf[20]; + static char buf[16]; const unsigned char *bytep = (const void *)&addrp->s_addr; sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]); -- cgit v1.2.3 From 6c689b639cf8e2aeced8685eca2915892d76ad86 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Mar 2022 12:25:21 +0100 Subject: Simplify static build extension loading Instead of guarding all calls to init_extensions*(), define stubs if not used. While at it, also add the missing prototypes for arp- and ebtables extension initializers. Signed-off-by: Phil Sutter --- include/xtables.h | 9 +++++++++ iptables/ip6tables-standalone.c | 3 --- iptables/iptables-restore.c | 4 ---- iptables/iptables-save.c | 4 ---- iptables/iptables-standalone.c | 2 -- iptables/xtables-arp.c | 3 --- iptables/xtables-eb.c | 3 --- iptables/xtables-monitor.c | 2 -- iptables/xtables-restore.c | 2 -- iptables/xtables-save.c | 2 -- iptables/xtables-standalone.c | 2 -- iptables/xtables-translate.c | 2 -- 12 files changed, 9 insertions(+), 29 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index ca674c26..044f191f 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -595,8 +595,17 @@ static inline void xtables_print_mark_mask(unsigned int mark, extern void init_extensions(void); extern void init_extensions4(void); extern void init_extensions6(void); + extern void init_extensionsa(void); + extern void init_extensionsb(void); #else # define _init __attribute__((constructor)) _INIT +# define EMPTY_FUNC_DEF(x) static inline void x(void) {} + EMPTY_FUNC_DEF(init_extensions) + EMPTY_FUNC_DEF(init_extensions4) + EMPTY_FUNC_DEF(init_extensions6) + EMPTY_FUNC_DEF(init_extensionsa) + EMPTY_FUNC_DEF(init_extensionsb) +# undef EMPTY_FUNC_DEF #endif extern const struct xtables_pprot xtables_chain_protos[]; diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c index 105b83ba..7c8bb0c2 100644 --- a/iptables/ip6tables-standalone.c +++ b/iptables/ip6tables-standalone.c @@ -52,11 +52,8 @@ ip6tables_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } - -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = do_command6(argc, argv, &table, &handle, false); if (ret) { diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 1917fb23..d8f65ce1 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -383,10 +383,8 @@ iptables_restore_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv); @@ -417,10 +415,8 @@ ip6tables_restore_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv); diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index a114e98b..a8dded63 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -227,10 +227,8 @@ iptables_save_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = do_iptables_save(&ipt_save_cb, argc, argv); @@ -273,10 +271,8 @@ ip6tables_save_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = do_iptables_save(&ip6t_save_cb, argc, argv); diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c index 8c67ea4d..0f263f6f 100644 --- a/iptables/iptables-standalone.c +++ b/iptables/iptables-standalone.c @@ -53,10 +53,8 @@ iptables_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = do_command4(argc, argv, &table, &handle, false); if (ret) { diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 805fb19a..9c44cfc2 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -205,10 +205,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname) arptables_globals.program_version); exit(1); } - -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensionsa(); -#endif if (nft_init(h, NFPROTO_ARP) < 0) xtables_error(OTHER_PROBLEM, diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 1e5b50ba..dcb707f6 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -668,10 +668,7 @@ int nft_init_eb(struct nft_handle *h, const char *pname) ebtables_globals.program_version); exit(1); } - -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensionsb(); -#endif if (nft_init(h, NFPROTO_BRIDGE) < 0) xtables_error(OTHER_PROBLEM, diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 73dc80c2..72d5e04b 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -625,11 +625,9 @@ int xtables_monitor_main(int argc, char *argv[]) xtables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); init_extensions6(); -#endif if (nft_init(&h, AF_INET)) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 81b25a43..c6a5ffed 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -363,11 +363,9 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthough, same table */ -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); init_extensions6(); -#endif break; case NFPROTO_ARP: case NFPROTO_BRIDGE: diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index 03d2b980..9bbe8511 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -202,11 +202,9 @@ xtables_save_main(int family, int argc, char *argv[], switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthough, same table */ -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); init_extensions6(); -#endif d.commit = true; break; case NFPROTO_ARP: diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 5482a856..06fedf26 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -67,7 +67,6 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) exit(1); } xt_params->program_name = progname; -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: @@ -79,7 +78,6 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) init_extensionsa(); break; } -#endif if (nft_init(&h, family) < 0) { fprintf(stderr, "%s: Failed to initialize nft: %s\n", diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 6a1cdac1..c5184334 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -488,11 +488,9 @@ static int xtables_xlate_main_common(struct nft_handle *h, switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthrough: same table */ -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); init_extensions6(); -#endif break; case NFPROTO_ARP: case NFPROTO_BRIDGE: -- cgit v1.2.3 From 0836524f093c0fd9c39604a46a949e43d9b47ef2 Mon Sep 17 00:00:00 2001 From: Etienne Champetier Date: Sun, 13 Mar 2022 20:09:12 -0400 Subject: xtables: Call init_extensions{,a,b}() for static builds Add calls to arp- and ebtables-specific extension loaders where missing. Also consistently call init_extensions() for them, as some extensions (ebtables 'limit' and arptables 'CLASSIFY' and 'MARK') live in libxt_* files. Signed-off-by: Etienne Champetier Signed-off-by: Phil Sutter --- iptables/xtables-arp.c | 1 + iptables/xtables-eb.c | 1 + iptables/xtables-monitor.c | 2 ++ iptables/xtables-restore.c | 5 +++++ iptables/xtables-save.c | 4 ++++ iptables/xtables-standalone.c | 5 +++++ iptables/xtables-translate.c | 11 ++++++++--- 7 files changed, 26 insertions(+), 3 deletions(-) diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 9c44cfc2..68514297 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -205,6 +205,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname) arptables_globals.program_version); exit(1); } + init_extensions(); init_extensionsa(); if (nft_init(h, NFPROTO_ARP) < 0) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index dcb707f6..a7bfb9c5 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -668,6 +668,7 @@ int nft_init_eb(struct nft_handle *h, const char *pname) ebtables_globals.program_version); exit(1); } + init_extensions(); init_extensionsb(); if (nft_init(h, NFPROTO_BRIDGE) < 0) diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 72d5e04b..8a04f4d1 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -628,6 +628,8 @@ int xtables_monitor_main(int argc, char *argv[]) init_extensions(); init_extensions4(); init_extensions6(); + init_extensionsa(); + init_extensionsb(); if (nft_init(&h, AF_INET)) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index c6a5ffed..0250ed7d 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -368,7 +368,12 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) init_extensions6(); break; case NFPROTO_ARP: + init_extensions(); + init_extensionsa(); + break; case NFPROTO_BRIDGE: + init_extensions(); + init_extensionsb(); break; default: fprintf(stderr, "Unknown family %d\n", family); diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index 9bbe8511..3b6b7e25 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -208,6 +208,8 @@ xtables_save_main(int family, int argc, char *argv[], d.commit = true; break; case NFPROTO_ARP: + init_extensions(); + init_extensionsa(); break; case NFPROTO_BRIDGE: { const char *ctr = getenv("EBTABLES_SAVE_COUNTER"); @@ -218,6 +220,8 @@ xtables_save_main(int family, int argc, char *argv[], d.format &= ~FMT_NOCOUNTS; d.format |= FMT_C_COUNTS | FMT_EBT_SAVE; } + init_extensions(); + init_extensionsb(); break; } default: diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 06fedf26..3faae02d 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -75,8 +75,13 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) init_extensions6(); break; case NFPROTO_ARP: + init_extensions(); init_extensionsa(); break; + case NFPROTO_BRIDGE: + init_extensions(); + init_extensionsb(); + break; } if (nft_init(&h, family) < 0) { diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index c5184334..07a9c1be 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -488,12 +488,17 @@ static int xtables_xlate_main_common(struct nft_handle *h, switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthrough: same table */ - init_extensions(); - init_extensions4(); - init_extensions6(); + init_extensions(); + init_extensions4(); + init_extensions6(); break; case NFPROTO_ARP: + init_extensions(); + init_extensionsa(); + break; case NFPROTO_BRIDGE: + init_extensions(); + init_extensionsb(); break; default: fprintf(stderr, "Unknown family %d\n", family); -- cgit v1.2.3 From c293e116fc6130baae9ed82ca122b69ee6ff8390 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Mar 2022 12:45:04 +0100 Subject: nft: Review static extension loading Combine the init_extensions() call common to all families, do not load IPv6 extensions for iptables and vice versa, drop the outdated comment about "same table". Signed-off-by: Phil Sutter --- iptables/xtables-restore.c | 7 +++---- iptables/xtables-save.c | 8 ++++---- iptables/xtables-standalone.c | 7 +++---- iptables/xtables-translate.c | 7 +++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 0250ed7d..b3cf4017 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -360,19 +360,18 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) p.in = stdin; } + init_extensions(); switch (family) { case NFPROTO_IPV4: - case NFPROTO_IPV6: /* fallthough, same table */ - init_extensions(); init_extensions4(); + break; + case NFPROTO_IPV6: init_extensions6(); break; case NFPROTO_ARP: - init_extensions(); init_extensionsa(); break; case NFPROTO_BRIDGE: - init_extensions(); init_extensionsb(); break; default: diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index 3b6b7e25..5a82cac5 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -199,16 +199,17 @@ xtables_save_main(int family, int argc, char *argv[], exit(1); } + init_extensions(); switch (family) { case NFPROTO_IPV4: - case NFPROTO_IPV6: /* fallthough, same table */ - init_extensions(); init_extensions4(); + d.commit = true; + break; + case NFPROTO_IPV6: init_extensions6(); d.commit = true; break; case NFPROTO_ARP: - init_extensions(); init_extensionsa(); break; case NFPROTO_BRIDGE: { @@ -220,7 +221,6 @@ xtables_save_main(int family, int argc, char *argv[], d.format &= ~FMT_NOCOUNTS; d.format |= FMT_C_COUNTS | FMT_EBT_SAVE; } - init_extensions(); init_extensionsb(); break; } diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 3faae02d..117b0c69 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -67,19 +67,18 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) exit(1); } xt_params->program_name = progname; + init_extensions(); switch (family) { case NFPROTO_IPV4: - case NFPROTO_IPV6: - init_extensions(); init_extensions4(); + break; + case NFPROTO_IPV6: init_extensions6(); break; case NFPROTO_ARP: - init_extensions(); init_extensionsa(); break; case NFPROTO_BRIDGE: - init_extensions(); init_extensionsb(); break; } diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 07a9c1be..d1e87f16 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -485,19 +485,18 @@ static int xtables_xlate_main_common(struct nft_handle *h, xtables_globals.program_version); return 1; } + init_extensions(); switch (family) { case NFPROTO_IPV4: - case NFPROTO_IPV6: /* fallthrough: same table */ - init_extensions(); init_extensions4(); + break; + case NFPROTO_IPV6: init_extensions6(); break; case NFPROTO_ARP: - init_extensions(); init_extensionsa(); break; case NFPROTO_BRIDGE: - init_extensions(); init_extensionsb(); break; default: -- cgit v1.2.3 From b555bfed542635259c489596630a75fce50aab1b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Mar 2022 13:15:49 +0100 Subject: tests: shell: Fix 0004-return-codes_0 for static builds In static builds, xtables_find_match() returns a slightly different error message if not found - make grep accept both. Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/iptables/0004-return-codes_0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 index dcd9dfd3..33c5f1f3 100755 --- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 @@ -39,7 +39,7 @@ 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=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory" -ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory" +ENOMTH=" v[0-9\.]* [^ ]*: Couldn't \(load\|find\) match \`foobar'\(:No such file or directory\|\)" ENOTBL=": can't initialize iptables table \`foobar': Table does not exist" # test chain creation -- cgit v1.2.3 From b1aee6b2238794446feba41778f88703784560f7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 16 Mar 2022 17:14:07 +0100 Subject: nft: Reject standard targets as chain names when restoring Reuse parse_chain() called from do_parse() for '-N' and rename it for a better description of what it does. Note that by itself, this patch will likely kill iptables-restore performance for big rulesets due to the extra extension lookup for chain lines. A following patch announcing those chains to libxtables will alleviate that. Signed-off-by: Phil Sutter Reviewed-by: Florian Westphal --- iptables/xshared.c | 4 ++-- iptables/xshared.h | 2 +- iptables/xtables-restore.c | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 43321d3b..00828c8a 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1031,7 +1031,7 @@ set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, } } -void parse_chain(const char *chainname) +void assert_valid_chain_name(const char *chainname) { const char *ptr; @@ -1412,7 +1412,7 @@ void do_parse(int argc, char *argv[], break; case 'N': - parse_chain(optarg); + assert_valid_chain_name(optarg); add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE, invert); p->chain = optarg; diff --git a/iptables/xshared.h b/iptables/xshared.h index 0de0e12e..ca761ee7 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -244,7 +244,7 @@ char cmd2char(int option); void add_command(unsigned int *cmd, const int newcmd, const int othercmds, int invert); int parse_rulenumber(const char *rule); -void parse_chain(const char *chainname); +void assert_valid_chain_name(const char *chainname); void generic_opt_check(int command, int options); char opt2char(int option); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index b3cf4017..b70a3cb1 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -155,10 +155,7 @@ static void xtables_restore_parse_line(struct nft_handle *h, "%s: line %u chain name invalid\n", xt_params->program_name, line); - if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s' (%u chars max)", - chain, XT_EXTENSION_MAXNAMELEN - 1); + assert_valid_chain_name(chain); policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); -- cgit v1.2.3 From f58b0d7406451afbb4b9b6c7888990c964fa7c79 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Dec 2020 15:40:56 +0100 Subject: libxtables: Implement notargets hash table Target lookup is relatively costly due to the filesystem access. Avoid this overhead in huge rulesets which contain many chain jumps by caching the failed lookups into a hashtable for later. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- libxtables/xtables.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 5f47f627..06090727 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -49,6 +49,7 @@ #include #include #include +#include #ifndef NO_SHARED_LIBS #include @@ -255,6 +256,71 @@ static void dlreg_free(void) } #endif +struct notarget { + struct hlist_node node; + char name[]; +}; + +#define NOTARGET_HSIZE 512 +static struct hlist_head notargets[NOTARGET_HSIZE]; + +static void notargets_hlist_init(void) +{ + int i; + + for (i = 0; i < NOTARGET_HSIZE; i++) + INIT_HLIST_HEAD(¬argets[i]); +} + +static void notargets_hlist_free(void) +{ + struct hlist_node *pos, *n; + struct notarget *cur; + int i; + + for (i = 0; i < NOTARGET_HSIZE; i++) { + hlist_for_each_entry_safe(cur, pos, n, ¬argets[i], node) { + hlist_del(&cur->node); + free(cur); + } + } +} + +static uint32_t djb_hash(const char *key) +{ + uint32_t i, hash = 5381; + + for (i = 0; i < strlen(key); i++) + hash = ((hash << 5) + hash) + key[i]; + + return hash; +} + +static struct notarget *notargets_hlist_lookup(const char *name) +{ + uint32_t key = djb_hash(name) % NOTARGET_HSIZE; + struct hlist_node *node; + struct notarget *cur; + + hlist_for_each_entry(cur, node, ¬argets[key], node) { + if (!strcmp(name, cur->name)) + return cur; + } + return NULL; +} + +static void notargets_hlist_insert(const char *name) +{ + struct notarget *cur; + + if (!name) + return; + + cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1); + strcpy(cur->name, name); + hlist_add_head(&cur->node, ¬argets[djb_hash(name) % NOTARGET_HSIZE]); +} + void xtables_init(void) { /* xtables cannot be used with setuid in a safe way. */ @@ -284,6 +350,8 @@ void xtables_init(void) return; } xtables_libdir = XTABLES_LIBDIR; + + notargets_hlist_init(); } void xtables_fini(void) @@ -291,6 +359,7 @@ void xtables_fini(void) #ifndef NO_SHARED_LIBS dlreg_free(); #endif + notargets_hlist_free(); } void xtables_set_nfproto(uint8_t nfproto) @@ -829,6 +898,10 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) || strcmp(name, XTC_LABEL_QUEUE) == 0 || strcmp(name, XTC_LABEL_RETURN) == 0) name = "standard"; + /* known non-target? */ + else if (notargets_hlist_lookup(name) && + tryload != XTF_LOAD_MUST_SUCCEED) + return NULL; /* Trigger delayed initialization */ for (dptr = &xtables_pending_targets; *dptr; ) { @@ -894,6 +967,8 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) if (ptr) ptr->used = 1; + else + notargets_hlist_insert(name); return ptr; } -- cgit v1.2.3 From ac4c84cc63d3cc021ca532692885a644fcde4518 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2022 12:50:01 +0100 Subject: libxtables: Boost rule target checks by announcing chain names When restoring a ruleset, feed libxtables with chain names from respective lines to avoid an extension search. While the user's intention is clear, this effectively disables the sanity check for clashes with target extensions. But: * The check yielded only a warning and the clashing chain was finally accepted. * Users crafting iptables dumps for feeding into iptables-restore likely know what they're doing. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- include/xtables.h | 3 +++ iptables/iptables-restore.c | 1 + iptables/xtables-restore.c | 1 + libxtables/xtables.c | 6 ++++++ 4 files changed, 11 insertions(+) diff --git a/include/xtables.h b/include/xtables.h index 044f191f..84369dac 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -654,6 +654,9 @@ const char *xt_xlate_get(struct xt_xlate *xl); #define xt_xlate_rule_get xt_xlate_get const char *xt_xlate_set_get(struct xt_xlate *xl); +/* informed target lookups */ +void xtables_announce_chain(const char *name); + #ifdef XTABLES_INTERNAL /* Shipped modules rely on this... */ diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index d8f65ce1..4410a587 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -308,6 +308,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, cb->ops->strerror(errno)); } + xtables_announce_chain(chain); ret = 1; } else if (in_table) { diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index b70a3cb1..1363f96a 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -155,6 +155,7 @@ static void xtables_restore_parse_line(struct nft_handle *h, "%s: line %u chain name invalid\n", xt_params->program_name, line); + xtables_announce_chain(chain); assert_valid_chain_name(chain); policy = strtok(NULL, " \t\n"); diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 06090727..96fd783a 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -321,6 +321,12 @@ static void notargets_hlist_insert(const char *name) hlist_add_head(&cur->node, ¬argets[djb_hash(name) % NOTARGET_HSIZE]); } +void xtables_announce_chain(const char *name) +{ + if (!notargets_hlist_lookup(name)) + notargets_hlist_insert(name); +} + void xtables_init(void) { /* xtables cannot be used with setuid in a safe way. */ -- cgit v1.2.3 From 24fff5d7de02ac4dcd288565f1527028a797fad5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Mar 2022 17:54:13 +0200 Subject: xlate-test: Fix for empty source line on failure The code overwrites 'line' before checking expected output. Save it in a temporary variable. Fixes: 62828a6aff231 ("tests: xlate-test: support multiline expectation") Signed-off-by: Phil Sutter --- xlate-test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xlate-test.py b/xlate-test.py index d78e8648..03bef7e2 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -42,6 +42,7 @@ def run_test(name, payload): line = payload.readline() while line: if line.startswith(keywords): + sourceline = line tests += 1 process = Popen([ xtables_nft_multi ] + shlex.split(line), stdout=PIPE, stderr=PIPE) (output, error) = process.communicate() @@ -58,7 +59,7 @@ def run_test(name, payload): test_passed = False failed += 1 result.append(name + ": " + red("Fail")) - result.append(magenta("src: ") + line.rstrip(" \n")) + result.append(magenta("src: ") + sourceline.rstrip(" \n")) result.append(magenta("exp: ") + expected) result.append(magenta("res: ") + translation + "\n") else: -- cgit v1.2.3 From 08c14fa6370bdf986476477075d43b4bcc0d26aa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Jan 2022 02:06:38 +0100 Subject: man: DNAT: Describe shifted port range feature This wasn't mentioned anywhere. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.man | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man index c3daea9a..e044c821 100644 --- a/extensions/libxt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -10,7 +10,7 @@ should be modified (and all future packets in this connection will also be mangled), and rules should cease being examined. It takes the following options: .TP -\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] +\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP[\fB/\fIbaseport\fP]]] which can specify a single new destination IP address, an inclusive range of IP addresses. Optionally a port range, if the rule also specifies one of the following protocols: @@ -18,6 +18,9 @@ if the rule also specifies one of the following protocols: If no port range is specified, then the destination port will never be modified. If no IP address is specified then only the destination port will be modified. +If \fBbaseport\fP is given, the difference of the original destination port and +its value is used as offset into the mapping port range. This allows to create +shifted portmap ranges and is available since kernel version 4.18. .TP \fB\-\-random\fP If option -- cgit v1.2.3 From 070a8626f2c01971d88bcfbcce10c914d552c9a4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Mar 2022 11:17:13 +0100 Subject: Revert "libipt_[SD]NAT: avoid false error about multiple destinations specified" This reverts commit f25b2355e889290879c8cecad3dd24ec0c384fb8. The workaround is not needed anymore since commit 30b178b9bf11e ("extensions: *NAT: Kill multiple IPv4 range support"). While being at it, drop the same hidden flag logic from libip6t_[SD]NAT extensions as well and just don't set XTOPT_MULTI so guided option parser will reject multiple parameters automatically. Signed-off-by: Phil Sutter --- extensions/libip6t_DNAT.c | 9 +-------- extensions/libip6t_SNAT.c | 9 +-------- extensions/libipt_DNAT.c | 8 ++------ extensions/libipt_SNAT.c | 3 --- 4 files changed, 4 insertions(+), 25 deletions(-) diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c index f1ad8143..d51994c0 100644 --- a/extensions/libip6t_DNAT.c +++ b/extensions/libip6t_DNAT.c @@ -19,10 +19,8 @@ enum { O_TO_DEST = 0, O_RANDOM, O_PERSISTENT, - O_X_TO_DEST, F_TO_DEST = 1 << O_TO_DEST, F_RANDOM = 1 << O_RANDOM, - F_X_TO_DEST = 1 << O_X_TO_DEST, }; static void DNAT_help(void) @@ -45,7 +43,7 @@ static void DNAT_help_v2(void) static const struct xt_option_entry DNAT_opts[] = { {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, + .flags = XTOPT_MAND}, {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, XTOPT_TABLEEND, @@ -183,12 +181,7 @@ static void _DNAT_parse(struct xt_option_call *cb, xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } parse_to(cb->arg, portok, range, rev); - cb->xflags |= F_X_TO_DEST; break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c index 6d19614c..4fe272b2 100644 --- a/extensions/libip6t_SNAT.c +++ b/extensions/libip6t_SNAT.c @@ -20,11 +20,9 @@ enum { O_RANDOM, O_RANDOM_FULLY, O_PERSISTENT, - O_X_TO_SRC, F_TO_SRC = 1 << O_TO_SRC, F_RANDOM = 1 << O_RANDOM, F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, - F_X_TO_SRC = 1 << O_X_TO_SRC, }; static void SNAT_help(void) @@ -38,7 +36,7 @@ static void SNAT_help(void) static const struct xt_option_entry SNAT_opts[] = { {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, + .flags = XTOPT_MAND}, {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, @@ -163,12 +161,7 @@ static void SNAT_parse(struct xt_option_call *cb) xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_SRC: - if (cb->xflags & F_X_TO_SRC) { - xtables_error(PARAMETER_PROBLEM, - "SNAT: Multiple --to-source not supported"); - } parse_to(cb->arg, portok, range); - cb->xflags |= F_X_TO_SRC; break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index eefa95eb..e93ab695 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -12,10 +12,8 @@ enum { O_TO_DEST = 0, O_RANDOM, O_PERSISTENT, - O_X_TO_DEST, /* hidden flag */ - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, - F_X_TO_DEST = 1 << O_X_TO_DEST, + F_TO_DEST = 1 << O_TO_DEST, + F_RANDOM = 1 << O_RANDOM, }; static void DNAT_help(void) @@ -145,7 +143,6 @@ static void DNAT_parse(struct xt_option_call *cb) switch (cb->entry->id) { case O_TO_DEST: parse_to(cb->arg, portok, mr->range); - cb->xflags |= F_X_TO_DEST; break; case O_PERSISTENT: mr->range->flags |= NF_NAT_RANGE_PERSISTENT; @@ -367,7 +364,6 @@ static void DNAT_parse_v2(struct xt_option_call *cb) switch (cb->entry->id) { case O_TO_DEST: parse_to_v2(cb->arg, portok, range); - cb->xflags |= F_X_TO_DEST; break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index bd36830a..211a20bc 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -13,11 +13,9 @@ enum { O_RANDOM, O_RANDOM_FULLY, O_PERSISTENT, - O_X_TO_SRC, F_TO_SRC = 1 << O_TO_SRC, F_RANDOM = 1 << O_RANDOM, F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, - F_X_TO_SRC = 1 << O_X_TO_SRC, }; static void SNAT_help(void) @@ -139,7 +137,6 @@ static void SNAT_parse(struct xt_option_call *cb) switch (cb->entry->id) { case O_TO_SRC: parse_to(cb->arg, portok, mr->range); - cb->xflags |= F_X_TO_SRC; break; case O_PERSISTENT: mr->range->flags |= NF_NAT_RANGE_PERSISTENT; -- cgit v1.2.3 From 3f4f1cf075572045a910b5c4d625602b9ba3c349 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 10 Jan 2022 16:39:53 +0100 Subject: extensions: ipt_DNAT: Merge v1 and v2 parsers Use v2 parser for both and copy field values into v1 data structure if needed. While being at it: * Introduce parse_ports() function similar to the one in libipt_REDIRECT.c. * Use xtables_strtoui() in the above instead of atoi() for integrated range checking. * Parse IP addresses using inet_pton(), writing directly into struct nf_nat_range2 fields. Signed-off-by: Phil Sutter --- extensions/libipt_DNAT.c | 290 ++++++++++++++++++----------------------------- 1 file changed, 111 insertions(+), 179 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index e93ab695..2a7b1bc4 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -5,6 +5,7 @@ #include #include /* get_kernel_version */ #include /* INT_MAX in ip_tables.h */ +#include #include #include @@ -42,54 +43,83 @@ static const struct xt_option_entry DNAT_opts[] = { XTOPT_TABLEEND, }; +/* Parses ports */ +static void +parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) +{ + unsigned int port, maxport, baseport; + char *end = NULL; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + switch (*end) { + case '\0': + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + return; + case '-': + arg = end + 1; + break; + case ':': + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash"); + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port value: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &maxport, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky", arg); + + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + + switch (*end) { + case '\0': + return; + case '/': + arg = end + 1; + break; + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port range: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + range->flags |= NF_NAT_RANGE_PROTO_OFFSET; + range->base_proto.tcp.port = htons(baseport); +} + /* Ranges expected in network order. */ static void -parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range) +parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) { - char *arg, *colon, *dash, *error; - const struct in_addr *ip; + char *arg, *colon, *dash; arg = xtables_strdup(orig_arg); colon = strchr(arg, ':'); if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + parse_ports(colon + 1, portok, range); - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min.tcp.port - = range->max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min.tcp.port = htons(port); - range->max.tcp.port = htons(maxport); - } /* Starts with a colon? No IP info...*/ if (colon == arg) { free(arg); @@ -106,46 +136,57 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range) if (dash) *dash = '\0'; - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range->min_ip = ip->s_addr; + if (!inet_pton(AF_INET, arg, &range->min_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"\n", arg); if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_ip = ip->s_addr; - } else - range->max_ip = range->min_ip; - + if (!inet_pton(AF_INET, dash + 1, &range->max_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"\n", dash + 1); + } else { + range->max_addr = range->min_addr; + } free(arg); return; } +static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, + struct nf_nat_range2 *range) +{ + bool portok = proto == IPPROTO_TCP || + proto == IPPROTO_UDP || + proto == IPPROTO_SCTP || + proto == IPPROTO_DCCP || + proto == IPPROTO_ICMP; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + parse_to(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + } +} + static void DNAT_parse(struct xt_option_call *cb) { struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; const struct ipt_entry *entry = cb->xt_entry; - int portok; + struct nf_nat_range2 range = {}; - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; + __DNAT_parse(cb, entry->ip.proto, &range); - xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_DEST: - parse_to(cb->arg, portok, mr->range); - break; + mr->range->min_ip = range.min_addr.ip; + mr->range->max_ip = range.max_addr.ip; + mr->range->min = range.min_proto; + mr->range->max = range.max_proto; + /* fall through */ case O_PERSISTENT: - mr->range->flags |= NF_NAT_RANGE_PERSISTENT; + mr->range->flags |= range.flags; break; } } @@ -159,6 +200,10 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; mr->rangesize = 1; + + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); } static void print_range(const struct nf_nat_ipv4_range *r) @@ -251,124 +296,11 @@ static int DNAT_xlate(struct xt_xlate *xl, return 1; } -static void -parse_to_v2(const char *orig_arg, int portok, struct nf_nat_range2 *range) -{ - char *arg, *colon, *dash, *error; - const struct in_addr *ip; - - arg = xtables_strdup(orig_arg); - - colon = strchr(arg, ':'); - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - char *slash; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - slash = strchr(dash, '/'); - if (slash) { - int baseport; - - baseport = atoi(slash + 1); - if (baseport <= 0 || baseport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", slash+1); - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); - } - } - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range->min_addr.in = *ip; - if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - static void DNAT_parse_v2(struct xt_option_call *cb) { const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_range2 *range = cb->data; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - parse_to_v2(cb->arg, portok, range); - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } + __DNAT_parse(cb, entry->ip.proto, cb->data); } static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -- cgit v1.2.3 From 7adef31421bc38c068e2e30720b61dc068c0d63f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Mar 2022 00:11:14 +0200 Subject: extensions: ipt_DNAT: Merge v1/v2 print/save code Turn print_range() function into sprint_range() so it becomes more versatile. Make it accept the new nf_nat_range2 data structure and make v1 callers convert their nf_nat_ipv4_multi_range_compat structs to that. This allows to introduce an inner __DNAT_print() which acts for v1 and v2 and prints either 'print' or 'save' syntax. Signed-off-by: Phil Sutter --- extensions/libipt_DNAT.c | 111 ++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 65 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index 2a7b1bc4..b72437d5 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -9,6 +9,15 @@ #include #include +#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) +#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ + .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ + .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ + .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ + .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ + .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ +}; + enum { O_TO_DEST = 0, O_RANDOM, @@ -206,51 +215,55 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) "Shifted portmap ranges not supported with this kernel"); } -static void print_range(const struct nf_nat_ipv4_range *r) +static char *sprint_range(const struct nf_nat_range2 *r) { - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; + static char buf[INET_ADDRSTRLEN * 2 + 1 + 6 * 3]; - a.s_addr = r->min_ip; - printf("%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - printf("-%s", xtables_ipaddr_to_numeric(&a)); - } + if (r->flags & NF_NAT_RANGE_MAP_IPS) { + sprintf(buf, "%s", xtables_ipaddr_to_numeric(&r->min_addr.in)); + if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) + sprintf(buf + strlen(buf), "-%s", + xtables_ipaddr_to_numeric(&r->max_addr.in)); + } else { + buf[0] = '\0'; } if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); + sprintf(buf + strlen(buf), ":%hu", + ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + sprintf(buf + strlen(buf), "-%hu", + ntohs(r->max_proto.tcp.port)); + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + sprintf(buf + strlen(buf), "/%hu", + ntohs(r->base_proto.tcp.port)); } + return buf; +} + +static void __DNAT_print(const struct nf_nat_range2 *r, bool save) +{ + const char *dashdash = save ? "--" : ""; + + printf(" %s%s", save ? "--to-destination " : "to:", sprint_range(r)); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", dashdash); + if (r->flags & NF_NAT_RANGE_PERSISTENT) + printf(" %spersistent", dashdash); } static void DNAT_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" to:"); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __DNAT_print(&range, false); } static void DNAT_save(const void *ip, const struct xt_entry_target *target) { - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" --to-destination "); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __DNAT_print(&range, true); } static void print_range_xlate(const struct nf_nat_ipv4_range *r, @@ -312,47 +325,15 @@ static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) range->flags |= NF_NAT_RANGE_PROTO_RANDOM; } -static void print_range_v2(const struct nf_nat_range2 *range) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - printf("%s", xtables_ipaddr_to_numeric(&range->min_addr.in)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ipaddr_to_numeric(&range->max_addr.in)); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - printf("/%hu", ntohs(range->base_proto.tcp.port)); - } -} - static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct nf_nat_range2 *range = (const void *)target->data; - - printf(" to:"); - print_range_v2(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); + __DNAT_print((const void *)target->data, false); } static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) { - const struct nf_nat_range2 *range = (const void *)target->data; - - printf(" --to-destination "); - print_range_v2(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); + __DNAT_print((const void *)target->data, true); } static void print_range_xlate_v2(const struct nf_nat_range2 *range, -- cgit v1.2.3 From 2e0c9a406d07fcff42b2e4345bf52600479989d6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Mar 2022 00:17:09 +0200 Subject: extensions: ipt_DNAT: Combine xlate functions also Make use of the new sprint_range() to introduce a common inner function for both v1 and v2 xlate functions. Also abort translation with shifted port ranges to not hide the missing feature in nftables. Signed-off-by: Phil Sutter --- extensions/libipt_DNAT.c | 88 ++++++++++++------------------------------------ 1 file changed, 21 insertions(+), 67 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index b72437d5..9a179919 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -266,47 +266,36 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target) __DNAT_print(&range, true); } -static void print_range_xlate(const struct nf_nat_ipv4_range *r, - struct xt_xlate *xl) +static int __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r) { - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; + char *range_str = sprint_range(r); + const char *sep = " "; - a.s_addr = r->min_ip; - xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a)); - } + /* shifted portmap ranges are not supported by nftables */ + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + return 0; + + xt_xlate_add(xl, "dnat"); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, "%srandom", sep); + sep = ","; } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, ":%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port)); + if (r->flags & NF_NAT_RANGE_PERSISTENT) { + xt_xlate_add(xl, "%spersistent", sep); + sep = ","; } + return 1; } static int DNAT_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "dnat to "); - print_range_xlate(mr->range, xl); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } + struct nf_nat_range2 range = + RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - return 1; + return __DNAT_xlate(xl, &range); } static void DNAT_parse_v2(struct xt_option_call *cb) @@ -336,45 +325,10 @@ static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) __DNAT_print((const void *)target->data, true); } -static void print_range_xlate_v2(const struct nf_nat_range2 *range, - struct xt_xlate *xl) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&range->min_addr.in)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) { - xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&range->max_addr.in)); - } - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - xt_xlate_add(xl, ";%hu", ntohs(range->base_proto.tcp.port)); - } -} - static int DNAT_xlate_v2(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct nf_nat_range2 *range = (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "dnat to "); - print_range_xlate_v2(range, xl); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (range->flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } - - return 1; + return __DNAT_xlate(xl, (const void *)params->target->data); } static struct xtables_target dnat_tg_reg[] = { -- cgit v1.2.3 From 9621318b8eb6242419ac67260ff0e56d6904c8d1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Mar 2022 19:49:43 +0100 Subject: extensions: DNAT: Rename from libipt to libxt Prepare for merge of libipt and libip6t DNAT extensions, allow for better code review. Signed-off-by: Phil Sutter --- extensions/libipt_DNAT.c | 370 ----------------------------------------------- extensions/libxt_DNAT.c | 370 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 370 insertions(+), 370 deletions(-) delete mode 100644 extensions/libipt_DNAT.c create mode 100644 extensions/libxt_DNAT.c diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c deleted file mode 100644 index 9a179919..00000000 --- a/extensions/libipt_DNAT.c +++ /dev/null @@ -1,370 +0,0 @@ -#include -#include -#include -#include -#include -#include /* get_kernel_version */ -#include /* INT_MAX in ip_tables.h */ -#include -#include -#include - -#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) -#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ - .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ - .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ - .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ - .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ - .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ -}; - -enum { - O_TO_DEST = 0, - O_RANDOM, - O_PERSISTENT, - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, -}; - -static void DNAT_help(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void DNAT_help_v2(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port[/port]]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static const struct xt_option_entry DNAT_opts[] = { - {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) -{ - unsigned int port, maxport, baseport; - char *end = NULL; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); - - switch (*end) { - case '\0': - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - return; - case '-': - arg = end + 1; - break; - case ':': - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash"); - default: - xtables_error(PARAMETER_PROBLEM, - "Garbage after port value: `%s'", end); - } - - if (!xtables_strtoui(arg, &end, &maxport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); - - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky", arg); - - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - switch (*end) { - case '\0': - return; - case '/': - arg = end + 1; - break; - default: - xtables_error(PARAMETER_PROBLEM, - "Garbage after port range: `%s'", end); - } - - if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); - - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); -} - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) -{ - char *arg, *colon, *dash; - - arg = xtables_strdup(orig_arg); - colon = strchr(arg, ':'); - - if (colon) { - parse_ports(colon + 1, portok, range); - - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - if (!inet_pton(AF_INET, arg, &range->min_addr)) - xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"\n", arg); - if (dash) { - if (!inet_pton(AF_INET, dash + 1, &range->max_addr)) - xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"\n", dash + 1); - } else { - range->max_addr = range->min_addr; - } - free(arg); - return; -} - -static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, - struct nf_nat_range2 *range) -{ - bool portok = proto == IPPROTO_TCP || - proto == IPPROTO_UDP || - proto == IPPROTO_SCTP || - proto == IPPROTO_DCCP || - proto == IPPROTO_ICMP; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - parse_to(cb->arg, portok, range); - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -static void DNAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_range2 range = {}; - - __DNAT_parse(cb, entry->ip.proto, &range); - - switch (cb->entry->id) { - case O_TO_DEST: - mr->range->min_ip = range.min_addr.ip; - mr->range->max_ip = range.max_addr.ip; - mr->range->min = range.min_proto; - mr->range->max = range.max_proto; - /* fall through */ - case O_PERSISTENT: - mr->range->flags |= range.flags; - break; - } -} - -static void DNAT_fcheck(struct xt_fcheck_call *cb) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - if ((cb->xflags & f) == f) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - - mr->rangesize = 1; - - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) - xtables_error(PARAMETER_PROBLEM, - "Shifted portmap ranges not supported with this kernel"); -} - -static char *sprint_range(const struct nf_nat_range2 *r) -{ - static char buf[INET_ADDRSTRLEN * 2 + 1 + 6 * 3]; - - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - sprintf(buf, "%s", xtables_ipaddr_to_numeric(&r->min_addr.in)); - if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) - sprintf(buf + strlen(buf), "-%s", - xtables_ipaddr_to_numeric(&r->max_addr.in)); - } else { - buf[0] = '\0'; - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - sprintf(buf + strlen(buf), ":%hu", - ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - sprintf(buf + strlen(buf), "-%hu", - ntohs(r->max_proto.tcp.port)); - if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) - sprintf(buf + strlen(buf), "/%hu", - ntohs(r->base_proto.tcp.port)); - } - return buf; -} - -static void __DNAT_print(const struct nf_nat_range2 *r, bool save) -{ - const char *dashdash = save ? "--" : ""; - - printf(" %s%s", save ? "--to-destination " : "to:", sprint_range(r)); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" %srandom", dashdash); - if (r->flags & NF_NAT_RANGE_PERSISTENT) - printf(" %spersistent", dashdash); -} - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_print(&range, false); -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_print(&range, true); -} - -static int __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r) -{ - char *range_str = sprint_range(r); - const char *sep = " "; - - /* shifted portmap ranges are not supported by nftables */ - if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) - return 0; - - xt_xlate_add(xl, "dnat"); - if (strlen(range_str)) - xt_xlate_add(xl, " to %s", range_str); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, "%srandom", sep); - sep = ","; - } - if (r->flags & NF_NAT_RANGE_PERSISTENT) { - xt_xlate_add(xl, "%spersistent", sep); - sep = ","; - } - return 1; -} - -static int DNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = - RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - - return __DNAT_xlate(xl, &range); -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - - __DNAT_parse(cb, entry->ip.proto, cb->data); -} - -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_range2 *range = cb->data; - - if ((cb->xflags & f) == f) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - __DNAT_print((const void *)target->data, false); -} - -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - __DNAT_print((const void *)target->data, true); -} - -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - return __DNAT_xlate(xl, (const void *)params->target->data); -} - -static struct xtables_target dnat_tg_reg[] = { - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 0, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = DNAT_help, - .print = DNAT_print, - .save = DNAT_save, - .x6_parse = DNAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNAT_print_v2, - .save = DNAT_save_v2, - .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, - }, -}; - -void _init(void) -{ - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); -} diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c new file mode 100644 index 00000000..9a179919 --- /dev/null +++ b/extensions/libxt_DNAT.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include +#include /* get_kernel_version */ +#include /* INT_MAX in ip_tables.h */ +#include +#include +#include + +#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) +#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ + .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ + .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ + .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ + .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ + .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ +}; + +enum { + O_TO_DEST = 0, + O_RANDOM, + O_PERSISTENT, + F_TO_DEST = 1 << O_TO_DEST, + F_RANDOM = 1 << O_RANDOM, +}; + +static void DNAT_help(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [[-]][:port[-port]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static void DNAT_help_v2(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [[-]][:port[-port[/port]]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static const struct xt_option_entry DNAT_opts[] = { + {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Parses ports */ +static void +parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) +{ + unsigned int port, maxport, baseport; + char *end = NULL; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + switch (*end) { + case '\0': + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + return; + case '-': + arg = end + 1; + break; + case ':': + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash"); + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port value: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &maxport, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky", arg); + + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + + switch (*end) { + case '\0': + return; + case '/': + arg = end + 1; + break; + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port range: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + + range->flags |= NF_NAT_RANGE_PROTO_OFFSET; + range->base_proto.tcp.port = htons(baseport); +} + +/* Ranges expected in network order. */ +static void +parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) +{ + char *arg, *colon, *dash; + + arg = xtables_strdup(orig_arg); + colon = strchr(arg, ':'); + + if (colon) { + parse_ports(colon + 1, portok, range); + + /* Starts with a colon? No IP info...*/ + if (colon == arg) { + free(arg); + return; + } + *colon = '\0'; + } + + range->flags |= NF_NAT_RANGE_MAP_IPS; + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + if (!inet_pton(AF_INET, arg, &range->min_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"\n", arg); + if (dash) { + if (!inet_pton(AF_INET, dash + 1, &range->max_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"\n", dash + 1); + } else { + range->max_addr = range->min_addr; + } + free(arg); + return; +} + +static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, + struct nf_nat_range2 *range) +{ + bool portok = proto == IPPROTO_TCP || + proto == IPPROTO_UDP || + proto == IPPROTO_SCTP || + proto == IPPROTO_DCCP || + proto == IPPROTO_ICMP; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + parse_to(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + } +} + +static void DNAT_parse(struct xt_option_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; + const struct ipt_entry *entry = cb->xt_entry; + struct nf_nat_range2 range = {}; + + __DNAT_parse(cb, entry->ip.proto, &range); + + switch (cb->entry->id) { + case O_TO_DEST: + mr->range->min_ip = range.min_addr.ip; + mr->range->max_ip = range.max_addr.ip; + mr->range->min = range.min_proto; + mr->range->max = range.max_proto; + /* fall through */ + case O_PERSISTENT: + mr->range->flags |= range.flags; + break; + } +} + +static void DNAT_fcheck(struct xt_fcheck_call *cb) +{ + static const unsigned int f = F_TO_DEST | F_RANDOM; + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + if ((cb->xflags & f) == f) + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + + mr->rangesize = 1; + + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + +static char *sprint_range(const struct nf_nat_range2 *r) +{ + static char buf[INET_ADDRSTRLEN * 2 + 1 + 6 * 3]; + + if (r->flags & NF_NAT_RANGE_MAP_IPS) { + sprintf(buf, "%s", xtables_ipaddr_to_numeric(&r->min_addr.in)); + if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) + sprintf(buf + strlen(buf), "-%s", + xtables_ipaddr_to_numeric(&r->max_addr.in)); + } else { + buf[0] = '\0'; + } + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + sprintf(buf + strlen(buf), ":%hu", + ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + sprintf(buf + strlen(buf), "-%hu", + ntohs(r->max_proto.tcp.port)); + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + sprintf(buf + strlen(buf), "/%hu", + ntohs(r->base_proto.tcp.port)); + } + return buf; +} + +static void __DNAT_print(const struct nf_nat_range2 *r, bool save) +{ + const char *dashdash = save ? "--" : ""; + + printf(" %s%s", save ? "--to-destination " : "to:", sprint_range(r)); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", dashdash); + if (r->flags & NF_NAT_RANGE_PERSISTENT) + printf(" %spersistent", dashdash); +} + +static void DNAT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __DNAT_print(&range, false); +} + +static void DNAT_save(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __DNAT_print(&range, true); +} + +static int __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r) +{ + char *range_str = sprint_range(r); + const char *sep = " "; + + /* shifted portmap ranges are not supported by nftables */ + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + return 0; + + xt_xlate_add(xl, "dnat"); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, "%srandom", sep); + sep = ","; + } + if (r->flags & NF_NAT_RANGE_PERSISTENT) { + xt_xlate_add(xl, "%spersistent", sep); + sep = ","; + } + return 1; +} + +static int DNAT_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = + RANGE2_INIT_FROM_IPV4_MRC(params->target->data); + + return __DNAT_xlate(xl, &range); +} + +static void DNAT_parse_v2(struct xt_option_call *cb) +{ + const struct ipt_entry *entry = cb->xt_entry; + + __DNAT_parse(cb, entry->ip.proto, cb->data); +} + +static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) +{ + static const unsigned int f = F_TO_DEST | F_RANDOM; + struct nf_nat_range2 *range = cb->data; + + if ((cb->xflags & f) == f) + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; +} + +static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + __DNAT_print((const void *)target->data, false); +} + +static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) +{ + __DNAT_print((const void *)target->data, true); +} + +static int DNAT_xlate_v2(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + return __DNAT_xlate(xl, (const void *)params->target->data); +} + +static struct xtables_target dnat_tg_reg[] = { + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = DNAT_help, + .print = DNAT_print, + .save = DNAT_save, + .x6_parse = DNAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNAT_print_v2, + .save = DNAT_save_v2, + .x6_parse = DNAT_parse_v2, + .x6_fcheck = DNAT_fcheck_v2, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate_v2, + }, +}; + +void _init(void) +{ + xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); +} -- cgit v1.2.3 From 14d77c8aa29a7b361d7830e40a7f75a05b29f717 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 19 Jan 2022 01:59:09 +0100 Subject: extensions: Merge IPv4 and IPv6 DNAT targets Make parse_to() family-aware so it serves for both IPv4 and IPv6. Have a core _DNAT_parse() function which parses into the most modern (nf_nat_range2) data structure and a bunch of wrappers to copy into legacy data structures if needed. Treat other callbacks analogous. Signed-off-by: Phil Sutter --- extensions/libip6t_DNAT.c | 402 ----------------------------------------- extensions/libip6t_DNAT.txlate | 11 -- extensions/libipt_DNAT.txlate | 14 -- extensions/libxt_DNAT.c | 224 ++++++++++++++++++----- extensions/libxt_DNAT.txlate | 35 ++++ 5 files changed, 218 insertions(+), 468 deletions(-) delete mode 100644 extensions/libip6t_DNAT.c delete mode 100644 extensions/libip6t_DNAT.txlate delete mode 100644 extensions/libipt_DNAT.txlate create mode 100644 extensions/libxt_DNAT.txlate diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c deleted file mode 100644 index d51994c0..00000000 --- a/extensions/libip6t_DNAT.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy - * - * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include -#include -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_DEST = 0, - O_RANDOM, - O_PERSISTENT, - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, -}; - -static void DNAT_help(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void DNAT_help_v2(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port[/port]]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static const struct xt_option_entry DNAT_opts[] = { - {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev) -{ - char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; - const struct in6_addr *ip; - - arg = xtables_strdup(orig_arg); - - start = strchr(arg, '['); - if (start == NULL) { - start = arg; - /* Lets assume one colon is port information. Otherwise its an IPv6 address */ - colon = strchr(arg, ':'); - if (colon && strchr(colon+1, ':')) - colon = NULL; - } - else { - start++; - end = strchr(start, ']'); - if (end == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid address format"); - - *end = '\0'; - colon = strchr(end + 1, ':'); - } - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - if (rev >= 2) { - char *slash = strchr(dash, '/'); - if (slash) { - int baseport; - - baseport = atoi(slash + 1); - if (baseport <= 0 || baseport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", slash+1); - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); - } - } - } - /* Starts with colon or [] colon? No IP info...*/ - if (colon == arg || colon == arg+2) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(start, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ip6addr(start); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - start); - range->min_addr.in6 = *ip; - if (dash) { - ip = xtables_numeric_to_ip6addr(dash + 1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in6 = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - -static void _DNAT_parse(struct xt_option_call *cb, - struct nf_nat_range2 *range, int rev) -{ - const struct ip6t_entry *entry = cb->xt_entry; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - parse_to(cb->arg, portok, range, rev); - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -static void DNAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_range *range_v1 = (void *)cb->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_parse(cb, &range, 1); - memcpy(range_v1, &range, sizeof(*range_v1)); -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - _DNAT_parse(cb, (struct nf_nat_range2 *)cb->data, 2); -} - -static void _DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - - if ((cb->xflags & f) == f) - *flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - -static void DNAT_fcheck(struct xt_fcheck_call *cb) -{ - _DNAT_fcheck(cb, &((struct nf_nat_range *)cb->data)->flags); -} - -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - _DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags); -} - -static void print_range(const struct nf_nat_range2 *range, int rev) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("["); - printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("]"); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (rev >= 2 && (range->flags & NF_NAT_RANGE_PROTO_OFFSET)) - printf("/%hu", ntohs(range->base_proto.tcp.port)); - } -} - -static void _DNAT_print(const struct nf_nat_range2 *range, int rev) -{ - printf(" to:"); - print_range(range, rev); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); -} - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range_v1 = (const void *)target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_print(&range, 1); -} - -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - _DNAT_print((const struct nf_nat_range2 *)target->data, 2); -} - -static void _DNAT_save(const struct nf_nat_range2 *range, int rev) -{ - printf(" --to-destination "); - print_range(range, rev); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range_v1 = (const void *)target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_save(&range, 1); -} - -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - _DNAT_save((const struct nf_nat_range2 *)target->data, 2); -} - -static void print_range_xlate(const struct nf_nat_range2 *range, - struct xt_xlate *xl, int rev) -{ - bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED; - - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - xt_xlate_add(xl, "%s%s%s", - proto_specified ? "[" : "", - xtables_ip6addr_to_numeric(&range->min_addr.in6), - proto_specified ? "]" : ""); - - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) { - xt_xlate_add(xl, "-%s%s%s", - proto_specified ? "[" : "", - xtables_ip6addr_to_numeric(&range->max_addr.in6), - proto_specified ? "]" : ""); - } - } - if (proto_specified) { - xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port)); - - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu", - ntohs(range->max_proto.tcp.port)); - } -} - -static int _DNAT_xlate(struct xt_xlate *xl, - const struct nf_nat_range2 *range, int rev) -{ - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "dnat to "); - print_range_xlate(range, xl, rev); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (range->flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } - - return 1; -} - -static int DNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *range_v1 = (const void *)params->target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_xlate(xl, &range, 1); - - return 1; -} - -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - _DNAT_xlate(xl, (const struct nf_nat_range2 *)params->target->data, 2); - - return 1; -} - -static struct xtables_target dnat_tg_reg[] = { - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 1, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = DNAT_help, - .print = DNAT_print, - .save = DNAT_save, - .x6_parse = DNAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNAT_print_v2, - .save = DNAT_save_v2, - .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, - }, -}; - -void _init(void) -{ - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); -} diff --git a/extensions/libip6t_DNAT.txlate b/extensions/libip6t_DNAT.txlate deleted file mode 100644 index 03c4caf7..00000000 --- a/extensions/libip6t_DNAT.txlate +++ /dev/null @@ -1,11 +0,0 @@ -ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 -nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80 - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent diff --git a/extensions/libipt_DNAT.txlate b/extensions/libipt_DNAT.txlate deleted file mode 100644 index e88314d9..00000000 --- a/extensions/libipt_DNAT.txlate +++ /dev/null @@ -1,14 +0,0 @@ -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 - -iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 -nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023 - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 9a179919..7f7c322c 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2011 Patrick McHardy + * + * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT + * funded by Astaro. + */ + #include #include #include @@ -7,6 +14,7 @@ #include /* INT_MAX in ip_tables.h */ #include #include +#include #include #define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) @@ -119,18 +127,36 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) /* Ranges expected in network order. */ static void -parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) +parse_to(const char *orig_arg, bool portok, + struct nf_nat_range2 *range, int family) { - char *arg, *colon, *dash; + char *arg, *start, *end, *colon, *dash; arg = xtables_strdup(orig_arg); - colon = strchr(arg, ':'); + start = strchr(arg, '['); + if (!start) { + start = arg; + /* Lets assume one colon is port information. + * Otherwise its an IPv6 address */ + colon = strchr(arg, ':'); + if (colon && strchr(colon + 1, ':')) + colon = NULL; + } else { + start++; + end = strchr(start, ']'); + if (end == NULL || family == AF_INET) + xtables_error(PARAMETER_PROBLEM, + "Invalid address format"); + + *end = '\0'; + colon = strchr(end + 1, ':'); + } if (colon) { parse_ports(colon + 1, portok, range); - /* Starts with a colon? No IP info...*/ - if (colon == arg) { + /* Starts with colon or [] colon? No IP info...*/ + if (colon == arg || colon == arg + 2) { free(arg); return; } @@ -138,20 +164,20 @@ parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) } range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); + dash = strchr(start, '-'); if (colon && dash && dash > colon) dash = NULL; if (dash) *dash = '\0'; - if (!inet_pton(AF_INET, arg, &range->min_addr)) + if (!inet_pton(family, start, &range->min_addr)) xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"\n", arg); + "Bad IP address \"%s\"", arg); if (dash) { - if (!inet_pton(AF_INET, dash + 1, &range->max_addr)) + if (!inet_pton(family, dash + 1, &range->max_addr)) xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"\n", dash + 1); + "Bad IP address \"%s\"", dash + 1); } else { range->max_addr = range->min_addr; } @@ -160,7 +186,7 @@ parse_to(const char *orig_arg, bool portok, struct nf_nat_range2 *range) } static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, - struct nf_nat_range2 *range) + struct nf_nat_range2 *range, int family) { bool portok = proto == IPPROTO_TCP || proto == IPPROTO_UDP || @@ -171,7 +197,7 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_DEST: - parse_to(cb->arg, portok, range); + parse_to(cb->arg, portok, range, family); break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; @@ -185,7 +211,7 @@ static void DNAT_parse(struct xt_option_call *cb) const struct ipt_entry *entry = cb->xt_entry; struct nf_nat_range2 range = {}; - __DNAT_parse(cb, entry->ip.proto, &range); + __DNAT_parse(cb, entry->ip.proto, &range, AF_INET); switch (cb->entry->id) { case O_TO_DEST: @@ -200,32 +226,47 @@ static void DNAT_parse(struct xt_option_call *cb) } } -static void DNAT_fcheck(struct xt_fcheck_call *cb) +static void __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) { static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; if ((cb->xflags & f) == f) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + *flags |= NF_NAT_RANGE_PROTO_RANDOM; +} + +static void DNAT_fcheck(struct xt_fcheck_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; mr->rangesize = 1; if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) xtables_error(PARAMETER_PROBLEM, "Shifted portmap ranges not supported with this kernel"); + + __DNAT_fcheck(cb, &mr->range[0].flags); } -static char *sprint_range(const struct nf_nat_range2 *r) +static char *sprint_range(const struct nf_nat_range2 *r, int family) { - static char buf[INET_ADDRSTRLEN * 2 + 1 + 6 * 3]; + bool brackets = family == AF_INET6 && + r->flags & NF_NAT_RANGE_PROTO_SPECIFIED; + static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3]; + + buf[0] = '\0'; if (r->flags & NF_NAT_RANGE_MAP_IPS) { - sprintf(buf, "%s", xtables_ipaddr_to_numeric(&r->min_addr.in)); - if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) - sprintf(buf + strlen(buf), "-%s", - xtables_ipaddr_to_numeric(&r->max_addr.in)); - } else { - buf[0] = '\0'; + if (brackets) + strcat(buf, "["); + inet_ntop(family, &r->min_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) { + strcat(buf, "-"); + inet_ntop(family, &r->max_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + } + if (brackets) + strcat(buf, "]"); } if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { sprintf(buf + strlen(buf), ":%hu", @@ -240,11 +281,12 @@ static char *sprint_range(const struct nf_nat_range2 *r) return buf; } -static void __DNAT_print(const struct nf_nat_range2 *r, bool save) +static void __DNAT_print(const struct nf_nat_range2 *r, bool save, int family) { const char *dashdash = save ? "--" : ""; - printf(" %s%s", save ? "--to-destination " : "to:", sprint_range(r)); + printf(" %s%s", save ? "--to-destination " : "to:", + sprint_range(r, family)); if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) printf(" %srandom", dashdash); if (r->flags & NF_NAT_RANGE_PERSISTENT) @@ -256,19 +298,20 @@ static void DNAT_print(const void *ip, const struct xt_entry_target *target, { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __DNAT_print(&range, false); + __DNAT_print(&range, false, AF_INET); } static void DNAT_save(const void *ip, const struct xt_entry_target *target) { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __DNAT_print(&range, true); + __DNAT_print(&range, true, AF_INET); } -static int __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r) +static int +__DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) { - char *range_str = sprint_range(r); + char *range_str = sprint_range(r, family); const char *sep = " "; /* shifted portmap ranges are not supported by nftables */ @@ -295,40 +338,109 @@ static int DNAT_xlate(struct xt_xlate *xl, struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - return __DNAT_xlate(xl, &range); + return __DNAT_xlate(xl, &range, AF_INET); } static void DNAT_parse_v2(struct xt_option_call *cb) { const struct ipt_entry *entry = cb->xt_entry; - __DNAT_parse(cb, entry->ip.proto, cb->data); + __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); } static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) { - static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_range2 *range = cb->data; - - if ((cb->xflags & f) == f) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + __DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags); } static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, int numeric) { - __DNAT_print((const void *)target->data, false); + __DNAT_print((const void *)target->data, false, AF_INET); } static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) { - __DNAT_print((const void *)target->data, true); + __DNAT_print((const void *)target->data, true, AF_INET); } static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) + const struct xt_xlate_tg_params *params) +{ + return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET); +} + +static void DNAT_parse6(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + struct nf_nat_range *range_v1 = (void *)cb->data; + struct nf_nat_range2 range = {}; + + memcpy(&range, range_v1, sizeof(*range_v1)); + __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); + memcpy(range_v1, &range, sizeof(*range_v1)); +} + +static void DNAT_fcheck6(struct xt_fcheck_call *cb) +{ + struct nf_nat_range *range = (void *)cb->data; + + if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); + + __DNAT_fcheck(cb, &range->flags); +} + +static void DNAT_print6(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __DNAT_print(&range, true, AF_INET6); +} + +static void DNAT_save6(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __DNAT_print(&range, true, AF_INET6); +} + +static int DNAT_xlate6(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)params->target->data, + sizeof(struct nf_nat_range)); + return __DNAT_xlate(xl, &range, AF_INET6); +} + +static void DNAT_parse6_v2(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + + __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); +} + +static void DNAT_print6_v2(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + __DNAT_print((const void *)target->data, true, AF_INET6); +} + +static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target) { - return __DNAT_xlate(xl, (const void *)params->target->data); + __DNAT_print((const void *)target->data, true, AF_INET6); +} + +static int DNAT_xlate6_v2(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); } static struct xtables_target dnat_tg_reg[] = { @@ -347,6 +459,21 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate, }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = DNAT_help, + .print = DNAT_print6, + .save = DNAT_save6, + .x6_parse = DNAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate6, + }, { .name = "DNAT", .version = XTABLES_VERSION, @@ -362,6 +489,21 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate_v2, }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNAT_print6_v2, + .save = DNAT_save6_v2, + .x6_parse = DNAT_parse6_v2, + .x6_fcheck = DNAT_fcheck_v2, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate6_v2, + }, }; void _init(void) diff --git a/extensions/libxt_DNAT.txlate b/extensions/libxt_DNAT.txlate new file mode 100644 index 00000000..a6597656 --- /dev/null +++ b/extensions/libxt_DNAT.txlate @@ -0,0 +1,35 @@ +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 +nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 + +iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 +nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 +nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023 + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random +nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent +nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent + +ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234 +nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234 + +ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234-fec0::2000 +nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000 + +ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 +nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80 + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234-fec0::2000]:1-20 +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20 + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent -- cgit v1.2.3 From 72d542b69ae2f780d9c9307231dcc3a2e3bed3b7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Mar 2022 14:42:51 +0100 Subject: extensions: Merge REDIRECT into DNAT Code is very similar, join them to reuse parsing code at least. As a side-effect, this enables parsing of service names for ports in DNAT as well as using port number 0 as that's what REDIRECT allows. Signed-off-by: Phil Sutter --- extensions/GNUmakefile.in | 4 +- extensions/libip6t_DNAT.t | 4 + extensions/libip6t_REDIRECT.c | 170 ------------------------------------ extensions/libip6t_REDIRECT.t | 6 -- extensions/libip6t_REDIRECT.txlate | 5 -- extensions/libipt_DNAT.t | 4 + extensions/libipt_REDIRECT.c | 174 ------------------------------------- extensions/libipt_REDIRECT.t | 6 -- extensions/libipt_REDIRECT.txlate | 5 -- extensions/libxt_DNAT.c | 164 +++++++++++++++++++++++++++++++--- extensions/libxt_REDIRECT.t | 16 ++++ extensions/libxt_REDIRECT.txlate | 26 ++++++ 12 files changed, 204 insertions(+), 380 deletions(-) delete mode 100644 extensions/libip6t_REDIRECT.c delete mode 100644 extensions/libip6t_REDIRECT.t delete mode 100644 extensions/libip6t_REDIRECT.txlate delete mode 100644 extensions/libipt_REDIRECT.c delete mode 100644 extensions/libipt_REDIRECT.t delete mode 100644 extensions/libipt_REDIRECT.txlate create mode 100644 extensions/libxt_REDIRECT.t create mode 100644 extensions/libxt_REDIRECT.txlate diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 956ccb38..6dad4e02 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -42,7 +42,7 @@ endif pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) @ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c))) @ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c))) -pfx_symlinks := NOTRACK state +pfx_symlinks := NOTRACK state REDIRECT @ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c))) @ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c))) pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod}) @@ -130,6 +130,8 @@ libxt_NOTRACK.so: libxt_CT.so ln -fs $< $@ libxt_state.so: libxt_conntrack.so ln -fs $< $@ +libxt_REDIRECT.so: libxt_DNAT.so + ln -fs $< $@ # Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD xt_RATEEST_LIBADD = -lm diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t index ec7d61f4..e53dfa16 100644 --- a/extensions/libip6t_DNAT.t +++ b/extensions/libip6t_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:ssh;-p tcp -j DNAT --to-destination [dead::beef]:22;OK +-p tcp -j DNAT --to-destination [dead::beef]:ftp-data;-p tcp -j DNAT --to-destination [dead::beef]:20;OK +-p tcp -j DNAT --to-destination [dead::beef]:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:10-20/ftp;-p tcp -j DNAT --to-destination [dead::beef]:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c deleted file mode 100644 index 8e04d2cd..00000000 --- a/extensions/libip6t_REDIRECT.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy - * - * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports [-]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_range *range) -{ - char *end = ""; - unsigned int port, maxport; - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range = (void *)(*cb->target)->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP - || entry->ipv6.proto == IPPROTO_UDP - || entry->ipv6.proto == IPPROTO_SCTP - || entry->ipv6.proto == IPPROTO_DCCP - || entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, range); - if (cb->xflags & F_RANDOM) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *range = (const void *)params->target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, "redirect to :%hu", - ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu ", - ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random "); - } - - return 1; -} - -static struct xtables_target redirect_tg_reg = { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = REDIRECT_help, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t deleted file mode 100644 index a0fb0ed1..00000000 --- a/extensions/libip6t_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -:PREROUTING,OUTPUT -*nat --p tcp -j REDIRECT --to-ports 42;=;OK --p udp -j REDIRECT --to-ports 42-1234;=;OK --p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK --j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libip6t_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate deleted file mode 100644 index 209f67a4..00000000 --- a/extensions/libip6t_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 - -ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t index 1c4413b9..9007572a 100644 --- a/extensions/libipt_DNAT.t +++ b/extensions/libipt_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:ssh;-p tcp -j DNAT --to-destination 1.1.1.1:22;OK +-p tcp -j DNAT --to-destination 1.1.1.1:ftp-data;-p tcp -j DNAT --to-destination 1.1.1.1:20;OK +-p tcp -j DNAT --to-destination 1.1.1.1:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:10-20/ftp;-p tcp -j DNAT --to-destination 1.1.1.1:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c deleted file mode 100644 index 7850306f..00000000 --- a/extensions/libipt_REDIRECT.c +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports [-]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static void REDIRECT_init(struct xt_entry_target *t) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; - - /* Actually, it's 0, but it's ignored at the moment. */ - mr->rangesize = 1; -} - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) -{ - char *end = ""; - unsigned int port, maxport; - - mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - mr->range[0].min.tcp.port - = mr->range[0].max.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - mr->range[0].min.tcp.port = htons(port); - mr->range[0].max.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, mr); - if (cb->xflags & F_RANDOM) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, "redirect to :%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - xt_xlate_add(xl, "-%hu ", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random "); - } - - return 1; -} - -static struct xtables_target redirect_tg_reg = { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = REDIRECT_help, - .init = REDIRECT_init, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t deleted file mode 100644 index a0fb0ed1..00000000 --- a/extensions/libipt_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -:PREROUTING,OUTPUT -*nat --p tcp -j REDIRECT --to-ports 42;=;OK --p udp -j REDIRECT --to-ports 42-1234;=;OK --p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK --j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libipt_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate deleted file mode 100644 index 815bb771..00000000 --- a/extensions/libipt_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 - -iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 7f7c322c..5ac8018c 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -28,10 +28,12 @@ enum { O_TO_DEST = 0, + O_TO_PORTS, O_RANDOM, O_PERSISTENT, - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, + F_TO_DEST = 1 << O_TO_DEST, + F_TO_PORTS = 1 << O_TO_PORTS, + F_RANDOM = 1 << O_RANDOM, }; static void DNAT_help(void) @@ -52,6 +54,15 @@ static void DNAT_help_v2(void) "[--random] [--persistent]\n"); } +static void REDIRECT_help(void) +{ + printf( +"REDIRECT target options:\n" +" --to-ports [-]\n" +" Port (range) to map to.\n" +" [--random]\n"); +} + static const struct xt_option_entry DNAT_opts[] = { {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, @@ -60,6 +71,12 @@ static const struct xt_option_entry DNAT_opts[] = { XTOPT_TABLEEND, }; +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + /* Parses ports */ static void parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) @@ -73,9 +90,13 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - if (!xtables_strtoui(arg, &end, &port, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) { + port = xtables_service_to_port(arg, NULL); + if (port == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + end = ""; + } switch (*end) { case '\0': @@ -94,9 +115,9 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) "Garbage after port value: `%s'", end); } - if (!xtables_strtoui(arg, &end, &maxport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + /* it is a range, don't allow service names here */ + if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg); if (maxport < port) /* People are stupid. */ @@ -117,9 +138,12 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) "Garbage after port range: `%s'", end); } - if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) { + baseport = xtables_service_to_port(arg, NULL); + if (baseport == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + } range->flags |= NF_NAT_RANGE_PROTO_OFFSET; range->base_proto.tcp.port = htons(baseport); @@ -199,6 +223,9 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, case O_TO_DEST: parse_to(cb->arg, portok, range, family); break; + case O_TO_PORTS: + parse_ports(cb->arg, portok, range); + break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; break; @@ -217,6 +244,8 @@ static void DNAT_parse(struct xt_option_call *cb) case O_TO_DEST: mr->range->min_ip = range.min_addr.ip; mr->range->max_ip = range.max_addr.ip; + /* fall through */ + case O_TO_PORTS: mr->range->min = range.min_proto; mr->range->max = range.max_proto; /* fall through */ @@ -228,9 +257,11 @@ static void DNAT_parse(struct xt_option_call *cb) static void __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) { - static const unsigned int f = F_TO_DEST | F_RANDOM; + static const unsigned int redir_f = F_TO_PORTS | F_RANDOM; + static const unsigned int dnat_f = F_TO_DEST | F_RANDOM; - if ((cb->xflags & f) == f) + if ((cb->xflags & redir_f) == redir_f || + (cb->xflags & dnat_f) == dnat_f) *flags |= NF_NAT_RANGE_PROTO_RANDOM; } @@ -443,6 +474,84 @@ static int DNAT_xlate6_v2(struct xt_xlate *xl, return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); } +static void __REDIRECT_print(const struct nf_nat_range2 *range, bool save) +{ + char *range_str = sprint_range(range, AF_INET); + const char *dashdash = save ? "--" : ""; + + if (strlen(range_str)) + /* range_str starts with colon, skip over them */ + printf(" %s %s", save ? "--to-ports" : "redir ports", + range_str + 1); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", dashdash); +} + +static int __REDIRECT_xlate(struct xt_xlate *xl, + const struct nf_nat_range2 *range) +{ + char *range_str = sprint_range(range, AF_INET); + + xt_xlate_add(xl, "redirect"); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + xt_xlate_add(xl, " random"); + + return 1; +} + +static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __REDIRECT_print(&range, false); +} + +static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __REDIRECT_print(&range, true); +} + +static int REDIRECT_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = + RANGE2_INIT_FROM_IPV4_MRC(params->target->data); + + return __REDIRECT_xlate(xl, &range); +} + +static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __REDIRECT_print(&range, false); +} + +static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __REDIRECT_print(&range, true); +} + +static int REDIRECT_xlate6(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)params->target->data, + sizeof(struct nf_nat_range)); + return __REDIRECT_xlate(xl, &range); +} + static struct xtables_target dnat_tg_reg[] = { { .name = "DNAT", @@ -459,6 +568,21 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate, }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = REDIRECT_help, + .print = REDIRECT_print, + .save = REDIRECT_save, + .x6_parse = DNAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate, + }, { .name = "DNAT", .version = XTABLES_VERSION, @@ -474,6 +598,20 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate6, }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = REDIRECT_help, + .print = REDIRECT_print6, + .save = REDIRECT_save6, + .x6_parse = DNAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate6, + }, { .name = "DNAT", .version = XTABLES_VERSION, diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t new file mode 100644 index 00000000..f607dd0a --- /dev/null +++ b/extensions/libxt_REDIRECT.t @@ -0,0 +1,16 @@ +:PREROUTING,OUTPUT +*nat +-p tcp -j REDIRECT --to-ports 42;=;OK +-p tcp -j REDIRECT --to-ports 0;=;OK +-p tcp -j REDIRECT --to-ports 65535;=;OK +-p tcp -j REDIRECT --to-ports 65536;;FAIL +-p udp -j REDIRECT --to-ports 0-0;-p udp -j REDIRECT --to-ports 0;OK +-p udp -j REDIRECT --to-ports 512-512;-p udp -j REDIRECT --to-ports 512;OK +-p udp -j REDIRECT --to-ports 42-1234;=;OK +-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK +-p tcp -j REDIRECT --to-ports 42-1234/567;;FAIL +-p tcp -j REDIRECT --to-ports ssh;-p tcp -j REDIRECT --to-ports 22;OK +-p tcp -j REDIRECT --to-ports ftp-data;-p tcp -j REDIRECT --to-ports 20;OK +-p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL +-p tcp -j REDIRECT --to-ports 10-ssh;;FAIL +-j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate new file mode 100644 index 00000000..2c536495 --- /dev/null +++ b/extensions/libxt_REDIRECT.txlate @@ -0,0 +1,26 @@ +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft add rule ip nat prerouting tcp dport 80 counter redirect + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :0 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0-65535 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :10-22 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft add rule ip6 nat prerouting tcp dport 80 counter redirect + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random -- cgit v1.2.3 From 18c96821b5901ac5c66dcbc5f299bd07ef5569ef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 31 Mar 2022 02:22:08 +0200 Subject: extensions: man: Document service name support in DNAT and REDIRECT Unless as part of a range, service names may be used. Point this out to avoid confusion. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.man | 2 ++ extensions/libxt_REDIRECT.man | 1 + 2 files changed, 3 insertions(+) diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man index e044c821..12d334af 100644 --- a/extensions/libxt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -21,6 +21,8 @@ will be modified. If \fBbaseport\fP is given, the difference of the original destination port and its value is used as offset into the mapping port range. This allows to create shifted portmap ranges and is available since kernel version 4.18. +For a single port or \fIbaseport\fP, a service name as listed in +\fB/etc/services\fP may be used. .TP \fB\-\-random\fP If option diff --git a/extensions/libxt_REDIRECT.man b/extensions/libxt_REDIRECT.man index 28d4d10b..10305597 100644 --- a/extensions/libxt_REDIRECT.man +++ b/extensions/libxt_REDIRECT.man @@ -16,6 +16,7 @@ This specifies a destination port or range of ports to use: without this, the destination port is never altered. This is only valid if the rule also specifies one of the following protocols: \fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. +For a single port, a service name as listed in \fB/etc/services\fP may be used. .TP \fB\-\-random\fP If option -- cgit v1.2.3 From 4c70c42fe8d937a2ca2709daa9efe96275d194da Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 21 Apr 2022 16:53:33 +0200 Subject: nft-shared: update context register for bitwise expression Update the destination register, otherwise nft_parse_cmp() gives up on interpreting the cmp expression when bitwise sreg != dreg. Fixes: 2c4a34c30cb4 ("iptables-compat: fix address prefix") Signed-off-by: Pablo Neira Ayuso --- iptables/nft-shared.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index c5721854..b3993211 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -460,6 +460,8 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) if (ctx->reg && reg != ctx->reg) return; + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); + ctx->reg = reg; data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); memcpy(ctx->bitwise.xor, data, len); data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); -- cgit v1.2.3 From aa92ec96078d09f9b3639109d7a24797ebb239ff Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 Apr 2022 21:34:47 +0200 Subject: nft: pass struct nft_xt_ctx to parse_meta() In preparation for native mark match support. Signed-off-by: Pablo Neira Ayuso --- iptables/nft-arp.c | 2 +- iptables/nft-bridge.c | 2 +- iptables/nft-ipv4.c | 2 +- iptables/nft-ipv6.c | 2 +- iptables/nft-shared.c | 6 +++--- iptables/nft-shared.h | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 028b06a6..89e64134 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -174,7 +174,7 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct arpt_entry *fw = &cs->arp; uint8_t flags = 0; - parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, + parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, fw->arp.outiface, fw->arp.outiface_mask, &flags); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index d4b66a25..097ef6e1 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -171,7 +171,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); + parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); switch (ctx->meta.key) { case NFT_META_BRI_IIFNAME: diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index af3d0c98..cf03edfa 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -144,7 +144,7 @@ static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, break; } - parse_meta(e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, cs->fw.ip.outiface, cs->fw.ip.outiface_mask, &cs->fw.ip.invflags); } diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 892a4854..5b767a40 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -117,7 +117,7 @@ static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, break; } - parse_meta(e, ctx->meta.key, cs->fw6.ipv6.iniface, + parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); } diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index b3993211..5b13b29c 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -261,9 +261,9 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned memset(mask, 0xff, len - 2); } -int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, - unsigned char *iniface_mask, char *outiface, - unsigned char *outiface_mask, uint8_t *invflags) +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, + char *outiface, unsigned char *outiface_mask, uint8_t *invflags) { uint32_t value; const void *ifname; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 7b337943..092958cd 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -156,9 +156,9 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, unsigned const char *b_iniface_mask, unsigned const char *b_outiface_mask); -int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, - unsigned char *iniface_mask, char *outiface, - unsigned char *outiface_mask, uint8_t *invflags); +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, char *outiface, + unsigned char *outiface_mask, uint8_t *invflags); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); void nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, -- cgit v1.2.3 From 94309632a13000e06ed02e08f0bcbed94080abb3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 Apr 2022 22:19:14 +0200 Subject: nft: native mark matching support Use meta mark + bitwise + cmp instead of nft_compat mark match. Signed-off-by: Pablo Neira Ayuso --- iptables/nft-shared.c | 36 ++++++++++++++++++++++++++++++++++++ iptables/nft.c | 23 +++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 5b13b29c..54a91180 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -261,6 +262,38 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned memset(mask, 0xff, len - 2); } +static struct xtables_match * +nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name); + +static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_mark_mtinfo1 *mark; + struct xtables_match *match; + uint32_t value; + + match = nft_create_match(ctx, ctx->cs, "mark"); + if (!match) + return -1; + + mark = (void*)match->m->data; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + mark->invert = 1; + + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + mark->mark = value; + if (ctx->flags & NFT_XT_CTX_BITWISE) { + memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask)); + ctx->flags &= ~NFT_XT_CTX_BITWISE; + } else { + mark->mask = 0xffffffff; + } + + return 0; +} + int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags) @@ -304,6 +337,9 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, parse_ifname(ifname, len, outiface, outiface_mask); break; + case NFT_META_MARK: + parse_meta_mark(ctx, e); + break; default: return -1; } diff --git a/iptables/nft.c b/iptables/nft.c index 6883662f..a629aeff 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -1406,6 +1407,26 @@ static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT); } +static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_match *m) +{ + struct xt_mark_mtinfo1 *mark = (void *)m->data; + int op; + + add_meta(r, NFT_META_MARK); + if (mark->mask != 0xffffffff) + add_bitwise(r, (uint8_t *)&mark->mask, sizeof(uint32_t)); + + if (mark->invert) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_cmp_u32(r, mark->mark, op); + + return 0; +} + int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1420,6 +1441,8 @@ int add_match(struct nft_handle *h, return add_nft_udp(r, m); else if (!strcmp(m->u.user.name, "tcp")) return add_nft_tcp(r, m); + else if (!strcmp(m->u.user.name, "mark")) + return add_nft_mark(h, r, m); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From 165cafec1d2c1cef3255995d4e610c638dd8bd5b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 Apr 2022 22:19:18 +0200 Subject: nft: pass handle to helper functions to build netlink payload Pass struct nft_handle to helper functions in preparation for the dynamic register allocation. Signed-off-by: Pablo Neira Ayuso --- iptables/nft-arp.c | 22 +++++++++++----------- iptables/nft-bridge.c | 24 +++++++++++++----------- iptables/nft-ipv4.c | 12 ++++++------ iptables/nft-ipv6.c | 10 +++++----- iptables/nft-shared.c | 31 ++++++++++++++++++------------- iptables/nft-shared.h | 14 +++++++------- iptables/nft.c | 26 +++++++++++++------------- 7 files changed, 73 insertions(+), 66 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 89e64134..8c5ce352 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -63,18 +63,18 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (fw->arp.iniface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN); - add_iniface(r, fw->arp.iniface, op); + add_iniface(h, r, fw->arp.iniface, op); } if (fw->arp.outiface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT); - add_outiface(r, fw->arp.outiface, op); + add_outiface(h, r, fw->arp.outiface, op); } if (fw->arp.arhrd != 0 || fw->arp.invflags & IPT_INV_ARPHRD) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD); - add_payload(r, offsetof(struct arphdr, ar_hrd), 2, + add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arhrd, op); } @@ -82,7 +82,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (fw->arp.arpro != 0 || fw->arp.invflags & IPT_INV_PROTO) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO); - add_payload(r, offsetof(struct arphdr, ar_pro), 2, + add_payload(h, r, offsetof(struct arphdr, ar_pro), 2, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arpro, op); } @@ -90,23 +90,23 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (fw->arp.arhln != 0 || fw->arp.invflags & IPT_INV_ARPHLN) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN); - add_proto(r, offsetof(struct arphdr, ar_hln), 1, + add_proto(h, r, offsetof(struct arphdr, ar_hln), 1, fw->arp.arhln, op); } - add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); + add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); if (fw->arp.arpop != 0 || fw->arp.invflags & IPT_INV_ARPOP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP); - add_payload(r, offsetof(struct arphdr, ar_op), 2, + add_payload(h, r, offsetof(struct arphdr, ar_op), 2, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arpop, op); } if (need_devaddr(&fw->arp.src_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr), &fw->arp.src_devaddr.addr, &fw->arp.src_devaddr.mask, @@ -118,7 +118,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, fw->arp.smsk.s_addr != 0 || fw->arp.invflags & IPT_INV_SRCIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln, &fw->arp.src.s_addr, &fw->arp.smsk.s_addr, sizeof(struct in_addr), op); @@ -127,7 +127,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (need_devaddr(&fw->arp.tgt_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr), &fw->arp.tgt_devaddr.addr, &fw->arp.tgt_devaddr.mask, @@ -138,7 +138,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, fw->arp.tmsk.s_addr != 0 || fw->arp.invflags & IPT_INV_DSTIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln, &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr, sizeof(struct in_addr), op); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 097ef6e1..888d4b6b 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -65,26 +65,28 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char xtables_print_mac_and_mask(mac, mask); } -static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op) +static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; iface_len = strlen(iface); - add_meta(r, NFT_META_BRI_IIFNAME); + add_meta(h, r, NFT_META_BRI_IIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); else add_cmp_ptr(r, op, iface, iface_len + 1); } -static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op) +static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; iface_len = strlen(iface); - add_meta(r, NFT_META_BRI_OIFNAME); + add_meta(h, r, NFT_META_BRI_OIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); else @@ -106,41 +108,41 @@ static int nft_bridge_add(struct nft_handle *h, if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); - add_iniface(r, fw->in, op); + add_iniface(h, r, fw->in, op); } if (fw->out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IOUT); - add_outiface(r, fw->out, op); + add_outiface(h, r, fw->out, op); } if (fw->logical_in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); - add_logical_iniface(r, fw->logical_in, op); + add_logical_iniface(h, r, fw->logical_in, op); } if (fw->logical_out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); - add_logical_outiface(r, fw->logical_out, op); + add_logical_outiface(h, r, fw->logical_out, op); } if (fw->bitmask & EBT_ISOURCE) { op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_addr(r, NFT_PAYLOAD_LL_HEADER, + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, offsetof(struct ethhdr, h_source), fw->sourcemac, fw->sourcemsk, ETH_ALEN, op); } if (fw->bitmask & EBT_IDEST) { op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_addr(r, NFT_PAYLOAD_LL_HEADER, + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, offsetof(struct ethhdr, h_dest), fw->destmac, fw->destmsk, ETH_ALEN, op); } if ((fw->bitmask & EBT_NOPROTO) == 0) { op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); - add_payload(r, offsetof(struct ethhdr, h_proto), 2, + add_payload(h, r, offsetof(struct ethhdr, h_proto), 2, NFT_PAYLOAD_LL_HEADER); add_cmp_u16(r, fw->ethproto, op); } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index cf03edfa..76a0e0de 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -35,35 +35,35 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, if (cs->fw.ip.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN); - add_iniface(r, cs->fw.ip.iniface, op); + add_iniface(h, r, cs->fw.ip.iniface, op); } if (cs->fw.ip.outiface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_OUT); - add_outiface(r, cs->fw.ip.outiface, op); + add_outiface(h, r, cs->fw.ip.outiface, op); } if (cs->fw.ip.proto != 0) { op = nft_invflags2cmp(cs->fw.ip.invflags, XT_INV_PROTO); - add_l4proto(r, cs->fw.ip.proto, op); + add_l4proto(h, r, cs->fw.ip.proto, op); } if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, saddr), &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, sizeof(struct in_addr), op); } if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, daddr), &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, sizeof(struct in_addr), op); } if (cs->fw.ip.flags & IPT_F_FRAG) { - add_payload(r, offsetof(struct iphdr, frag_off), 2, + add_payload(h, r, offsetof(struct iphdr, frag_off), 2, NFT_PAYLOAD_NETWORK_HEADER); /* get the 13 bits that contain the fragment offset */ add_bitwise_u16(r, htons(0x1fff), 0); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 5b767a40..9a29d18b 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -34,24 +34,24 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, if (cs->fw6.ipv6.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); - add_iniface(r, cs->fw6.ipv6.iniface, op); + add_iniface(h, r, cs->fw6.ipv6.iniface, op); } if (cs->fw6.ipv6.outiface[0] != '\0') { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); - add_outiface(r, cs->fw6.ipv6.outiface, op); + add_outiface(h, r, cs->fw6.ipv6.outiface, op); } if (cs->fw6.ipv6.proto != 0) { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); - add_l4proto(r, cs->fw6.ipv6.proto, op); + add_l4proto(h, r, cs->fw6.ipv6.proto, op); } if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) || (cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct ip6_hdr, ip6_src), &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, sizeof(struct in6_addr), op); @@ -60,7 +60,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) || (cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct ip6_hdr, ip6_dst), &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, sizeof(struct in6_addr), op); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 54a91180..52821684 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -40,7 +40,7 @@ extern struct nft_family_ops nft_family_ops_ipv6; extern struct nft_family_ops nft_family_ops_arp; extern struct nft_family_ops nft_family_ops_bridge; -void add_meta(struct nftnl_rule *r, uint32_t key) +void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key) { struct nftnl_expr *expr; @@ -54,7 +54,8 @@ void add_meta(struct nftnl_rule *r, uint32_t key) nftnl_rule_add_expr(r, expr); } -void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base) +void add_payload(struct nft_handle *h, struct nftnl_rule *r, + int offset, int len, uint32_t base) { struct nftnl_expr *expr; @@ -136,13 +137,14 @@ void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op) add_cmp_ptr(r, op, &val, sizeof(val)); } -void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op) +void add_iniface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; iface_len = strlen(iface); - add_meta(r, NFT_META_IIFNAME); + add_meta(h, r, NFT_META_IIFNAME); if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1); @@ -150,13 +152,14 @@ void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op) add_cmp_ptr(r, op, iface, iface_len + 1); } -void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op) +void add_outiface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; iface_len = strlen(iface); - add_meta(r, NFT_META_OIFNAME); + add_meta(h, r, NFT_META_OIFNAME); if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1); @@ -164,7 +167,8 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op) add_cmp_ptr(r, op, iface, iface_len + 1); } -void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, +void add_addr(struct nft_handle *h, struct nftnl_rule *r, + enum nft_payload_bases base, int offset, void *data, void *mask, size_t len, uint32_t op) { const unsigned char *m = mask; @@ -183,7 +187,7 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, if (!bitwise) len = i; - add_payload(r, offset, len, base); + add_payload(h, r, offset, len, base); if (bitwise) add_bitwise(r, mask, len); @@ -191,16 +195,17 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, add_cmp_ptr(r, op, data, len); } -void add_proto(struct nftnl_rule *r, int offset, size_t len, - uint8_t proto, uint32_t op) +void add_proto(struct nft_handle *h, struct nftnl_rule *r, + int offset, size_t len, uint8_t proto, uint32_t op) { - add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); + add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u8(r, proto, op); } -void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op) +void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, + uint8_t proto, uint32_t op) { - add_meta(r, NFT_META_L4PROTO); + add_meta(h, r, NFT_META_L4PROTO); add_cmp_u8(r, proto, op); } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 092958cd..0bdb6848 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -132,21 +132,21 @@ struct nft_family_ops { int rulenum); }; -void add_meta(struct nftnl_rule *r, uint32_t key); -void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base); +void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key); +void add_payload(struct nft_handle *h, struct nftnl_rule *r, int offset, int len, uint32_t base); void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len); void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor); void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len); void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op); void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op); void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op); -void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op); -void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op); -void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, +void add_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); +void add_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); +void add_addr(struct nft_handle *h, struct nftnl_rule *r, enum nft_payload_bases base, int offset, void *data, void *mask, size_t len, uint32_t op); -void add_proto(struct nftnl_rule *r, int offset, size_t len, +void add_proto(struct nft_handle *h, struct nftnl_rule *r, int offset, size_t len, uint8_t proto, uint32_t op); -void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op); +void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, uint8_t proto, uint32_t op); void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv); bool is_same_interfaces(const char *a_iniface, const char *a_outiface, diff --git a/iptables/nft.c b/iptables/nft.c index a629aeff..987b3c95 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1216,7 +1216,7 @@ static int add_nft_among(struct nft_handle *h, (data->dst.cnt && data->dst.ip)) { uint16_t eth_p_ip = htons(ETH_P_IP); - add_meta(r, NFT_META_PROTOCOL); + add_meta(h, r, NFT_META_PROTOCOL); add_cmp_ptr(r, NFT_CMP_EQ, ð_p_ip, 2); } @@ -1263,11 +1263,9 @@ static int expr_gen_range_cmp16(struct nftnl_rule *r, return 0; } -static int add_nft_tcpudp(struct nftnl_rule *r, - uint16_t src[2], - bool invert_src, - uint16_t dst[2], - bool invert_dst) +static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r, + uint16_t src[2], bool invert_src, + uint16_t dst[2], bool invert_dst) { struct nftnl_expr *expr; uint8_t op = NFT_CMP_EQ; @@ -1332,7 +1330,8 @@ static bool udp_all_zero(const struct xt_udp *u) return memcmp(u, &zero, sizeof(*u)) == 0; } -static int add_nft_udp(struct nftnl_rule *r, struct xt_entry_match *m) +static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_match *m) { struct xt_udp *udp = (void *)m->data; @@ -1346,7 +1345,7 @@ static int add_nft_udp(struct nftnl_rule *r, struct xt_entry_match *m) return ret; } - return add_nft_tcpudp(r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT, + return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT, udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } @@ -1380,7 +1379,8 @@ static bool tcp_all_zero(const struct xt_tcp *t) return memcmp(t, &zero, sizeof(*t)) == 0; } -static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) +static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_match *m) { static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS; struct xt_tcp *tcp = (void *)m->data; @@ -1403,7 +1403,7 @@ static int add_nft_tcp(struct nftnl_rule *r, struct xt_entry_match *m) return ret; } - return add_nft_tcpudp(r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT, + return add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT, tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT); } @@ -1413,7 +1413,7 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, struct xt_mark_mtinfo1 *mark = (void *)m->data; int op; - add_meta(r, NFT_META_MARK); + add_meta(h, r, NFT_META_MARK); if (mark->mask != 0xffffffff) add_bitwise(r, (uint8_t *)&mark->mask, sizeof(uint32_t)); @@ -1438,9 +1438,9 @@ int add_match(struct nft_handle *h, else if (!strcmp(m->u.user.name, "among")) return add_nft_among(h, r, m); else if (!strcmp(m->u.user.name, "udp")) - return add_nft_udp(r, m); + return add_nft_udp(h, r, m); else if (!strcmp(m->u.user.name, "tcp")) - return add_nft_tcp(r, m); + return add_nft_tcp(h, r, m); else if (!strcmp(m->u.user.name, "mark")) return add_nft_mark(h, r, m); -- cgit v1.2.3 From 7e38890c6b4fb5c03d436a0a8b9f3f31d65f75a4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 Apr 2022 22:19:20 +0200 Subject: nft: prepare for dynamic register allocation Store the register that has been allocated and pass it on to the next expression. NFT_REG_1 is still used. No functional changes are expected. Signed-off-by: Pablo Neira Ayuso --- iptables/nft-arp.c | 18 ++++++---- iptables/nft-bridge.c | 20 ++++++----- iptables/nft-ipv4.c | 8 +++-- iptables/nft-shared.c | 99 +++++++++++++++++++++++++++++++-------------------- iptables/nft-shared.h | 16 ++++----- iptables/nft.c | 70 ++++++++++++++++++++---------------- 6 files changed, 137 insertions(+), 94 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 8c5ce352..65bd965e 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -73,18 +73,22 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (fw->arp.arhrd != 0 || fw->arp.invflags & IPT_INV_ARPHRD) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD); add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arhrd, op); + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arhrd, op, reg); } if (fw->arp.arpro != 0 || fw->arp.invflags & IPT_INV_PROTO) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO); add_payload(h, r, offsetof(struct arphdr, ar_pro), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpro, op); + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arpro, op, reg); } if (fw->arp.arhln != 0 || @@ -98,10 +102,12 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, if (fw->arp.arpop != 0 || fw->arp.invflags & IPT_INV_ARPOP) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP); add_payload(h, r, offsetof(struct arphdr, ar_op), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpop, op); + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arpop, op, reg); } if (need_devaddr(&fw->arp.src_devaddr)) { diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 888d4b6b..106bcc72 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -69,28 +69,30 @@ static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(h, r, NFT_META_BRI_IIFNAME); + add_meta(h, r, NFT_META_BRI_IIFNAME, ®); if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len + 1, reg); } static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(h, r, NFT_META_BRI_OIFNAME); + add_meta(h, r, NFT_META_BRI_OIFNAME, ®); if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len + 1, reg); } static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) @@ -141,10 +143,12 @@ static int nft_bridge_add(struct nft_handle *h, } if ((fw->bitmask & EBT_NOPROTO) == 0) { + uint8_t reg; + op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); add_payload(h, r, offsetof(struct ethhdr, h_proto), 2, - NFT_PAYLOAD_LL_HEADER); - add_cmp_u16(r, fw->ethproto, op); + NFT_PAYLOAD_LL_HEADER, ®); + add_cmp_u16(r, fw->ethproto, op, reg); } add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO); diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 76a0e0de..59c4a41f 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -63,17 +63,19 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, sizeof(struct in_addr), op); } if (cs->fw.ip.flags & IPT_F_FRAG) { + uint8_t reg; + add_payload(h, r, offsetof(struct iphdr, frag_off), 2, - NFT_PAYLOAD_NETWORK_HEADER); + NFT_PAYLOAD_NETWORK_HEADER, ®); /* get the 13 bits that contain the fragment offset */ - add_bitwise_u16(r, htons(0x1fff), 0); + add_bitwise_u16(h, r, htons(0x1fff), 0, reg, ®); /* if offset is non-zero, this is a fragment */ op = NFT_CMP_NEQ; if (cs->fw.ip.invflags & IPT_INV_FRAG) op = NFT_CMP_EQ; - add_cmp_u16(r, 0, op); + add_cmp_u16(r, 0, op, reg); } add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 52821684..27e95c1a 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -40,74 +40,89 @@ extern struct nft_family_ops nft_family_ops_ipv6; extern struct nft_family_ops nft_family_ops_arp; extern struct nft_family_ops nft_family_ops_bridge; -void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key) +void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, + uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; expr = nftnl_expr_alloc("meta"); if (expr == NULL) return; + reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key); - nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); - + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, reg); nftnl_rule_add_expr(r, expr); + + *dreg = reg; } void add_payload(struct nft_handle *h, struct nftnl_rule *r, - int offset, int len, uint32_t base) + int offset, int len, uint32_t base, uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; expr = nftnl_expr_alloc("payload"); if (expr == NULL) return; + reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); - nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } /* bitwise operation is = sreg & mask ^ xor */ -void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor) +void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, + uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; expr = nftnl_expr_alloc("bitwise"); if (expr == NULL) return; - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); + reg = NFT_REG_1; + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t)); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } -void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len) +void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, + uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg) { struct nftnl_expr *expr; uint32_t xor[4] = { 0 }; + uint8_t reg = *dreg; expr = nftnl_expr_alloc("bitwise"); if (expr == NULL) return; - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } -void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len) +void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, + uint8_t sreg) { struct nftnl_expr *expr; @@ -115,56 +130,59 @@ void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len) if (expr == NULL) return; - nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len); - nftnl_rule_add_expr(r, expr); } -void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op) +void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op) +void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op) +void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } void add_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(h, r, NFT_META_IIFNAME); + add_meta(h, r, NFT_META_IIFNAME, ®); if (iface[iface_len - 1] == '+') { if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1); - } else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); + } else { + add_cmp_ptr(r, op, iface, iface_len + 1, reg); + } } void add_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(h, r, NFT_META_OIFNAME); + add_meta(h, r, NFT_META_OIFNAME, ®); if (iface[iface_len - 1] == '+') { if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1); - } else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); + } else { + add_cmp_ptr(r, op, iface, iface_len + 1, reg); + } } void add_addr(struct nft_handle *h, struct nftnl_rule *r, @@ -173,6 +191,7 @@ void add_addr(struct nft_handle *h, struct nftnl_rule *r, { const unsigned char *m = mask; bool bitwise = false; + uint8_t reg; int i, j; for (i = 0; i < len; i++) { @@ -187,26 +206,30 @@ void add_addr(struct nft_handle *h, struct nftnl_rule *r, if (!bitwise) len = i; - add_payload(h, r, offset, len, base); + add_payload(h, r, offset, len, base, ®); if (bitwise) - add_bitwise(r, mask, len); + add_bitwise(h, r, mask, len, reg, ®); - add_cmp_ptr(r, op, data, len); + add_cmp_ptr(r, op, data, len, reg); } void add_proto(struct nft_handle *h, struct nftnl_rule *r, int offset, size_t len, uint8_t proto, uint32_t op) { - add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u8(r, proto, op); + uint8_t reg; + + add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u8(r, proto, op, reg); } void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, uint8_t proto, uint32_t op) { - add_meta(h, r, NFT_META_L4PROTO); - add_cmp_u8(r, proto, op); + uint8_t reg; + + add_meta(h, r, NFT_META_L4PROTO, ®); + add_cmp_u8(r, proto, op, reg); } bool is_same_interfaces(const char *a_iniface, const char *a_outiface, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0bdb6848..b0404904 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -132,14 +132,14 @@ struct nft_family_ops { int rulenum); }; -void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key); -void add_payload(struct nft_handle *h, struct nftnl_rule *r, int offset, int len, uint32_t base); -void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len); -void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor); -void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len); -void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op); -void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op); -void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op); +void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, uint8_t *dreg); +void add_payload(struct nft_handle *h, struct nftnl_rule *r, int offset, int len, uint32_t base, uint8_t *dreg); +void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg); +void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg); +void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, uint8_t sreg); +void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg); +void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg); +void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg); void add_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); void add_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); void add_addr(struct nft_handle *h, struct nftnl_rule *r, enum nft_payload_bases base, int offset, diff --git a/iptables/nft.c b/iptables/nft.c index 987b3c95..bdfef024 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1090,16 +1090,22 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table, } static struct nftnl_expr * -gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg) +gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len, + uint8_t *dreg) { struct nftnl_expr *e = nftnl_expr_alloc("payload"); + uint8_t reg; if (!e) return NULL; + + reg = NFT_REG_1; nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len); - nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg); + nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, reg); + *dreg = reg; + return e; } @@ -1144,6 +1150,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table, struct nftnl_expr *e; struct nftnl_set *s; uint32_t flags = 0; + uint8_t reg; int idx = 0; if (ip) { @@ -1184,21 +1191,22 @@ static int __add_nft_among(struct nft_handle *h, const char *table, nftnl_set_elem_add(s, elem); } - e = gen_payload(NFT_PAYLOAD_LL_HEADER, - eth_addr_off[dst], ETH_ALEN, NFT_REG_1); + e = gen_payload(h, NFT_PAYLOAD_LL_HEADER, + eth_addr_off[dst], ETH_ALEN, ®); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); if (ip) { - e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], - sizeof(struct in_addr), NFT_REG32_02); + e = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], + sizeof(struct in_addr), ®); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); } - e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv); + reg = NFT_REG_1; + e = gen_lookup(reg, "__set%d", set_id, inv); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); @@ -1215,9 +1223,10 @@ static int add_nft_among(struct nft_handle *h, if ((data->src.cnt && data->src.ip) || (data->dst.cnt && data->dst.ip)) { uint16_t eth_p_ip = htons(ETH_P_IP); + uint8_t reg; - add_meta(h, r, NFT_META_PROTOCOL); - add_cmp_ptr(r, NFT_CMP_EQ, ð_p_ip, 2); + add_meta(h, r, NFT_META_PROTOCOL, ®); + add_cmp_ptr(r, NFT_CMP_EQ, ð_p_ip, 2, reg); } if (data->src.cnt) @@ -1233,17 +1242,17 @@ static int add_nft_among(struct nft_handle *h, static int expr_gen_range_cmp16(struct nftnl_rule *r, uint16_t lo, uint16_t hi, - bool invert) + bool invert, uint8_t reg) { struct nftnl_expr *e; if (lo == hi) { - add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ); + add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg); return 0; } if (lo == 0 && hi < 0xffff) { - add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE); + add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE, reg); return 0; } @@ -1251,7 +1260,7 @@ static int expr_gen_range_cmp16(struct nftnl_rule *r, if (!e) return -ENOMEM; - nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, NFT_REG_1); + nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, reg); nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_OP, invert ? NFT_RANGE_NEQ : NFT_RANGE_EQ); lo = htons(lo); @@ -1269,6 +1278,7 @@ static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r, { struct nftnl_expr *expr; uint8_t op = NFT_CMP_EQ; + uint8_t reg; int ret; if (src[0] && src[0] == src[1] && @@ -1279,36 +1289,33 @@ static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r, if (invert_src) op = NFT_CMP_NEQ; - expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, - NFT_REG_1); + expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, ®); if (!expr) return -ENOMEM; nftnl_rule_add_expr(r, expr); - add_cmp_u32(r, htonl(combined), op); + add_cmp_u32(r, htonl(combined), op, reg); return 0; } if (src[0] || src[1] < 0xffff) { - expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, - 0, 2, NFT_REG_1); + expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 2, ®); if (!expr) return -ENOMEM; nftnl_rule_add_expr(r, expr); - ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src); + ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src, reg); if (ret) return ret; } if (dst[0] || dst[1] < 0xffff) { - expr = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, - 2, 2, NFT_REG_1); + expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 2, 2, ®); if (!expr) return -ENOMEM; nftnl_rule_add_expr(r, expr); - ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst); + ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst, reg); if (ret) return ret; } @@ -1349,22 +1356,22 @@ static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r, udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } -static int add_nft_tcpflags(struct nftnl_rule *r, +static int add_nft_tcpflags(struct nft_handle *h, struct nftnl_rule *r, uint8_t cmp, uint8_t mask, bool invert) { struct nftnl_expr *e; + uint8_t reg; - e = gen_payload(NFT_PAYLOAD_TRANSPORT_HEADER, - 13, 1, NFT_REG_1); + e = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 13, 1, ®); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); - add_bitwise(r, &mask, 1); - add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ); + add_bitwise(h, r, &mask, 1, reg, ®); + add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg); return 0; } @@ -1396,7 +1403,7 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r, } if (tcp->flg_mask) { - int ret = add_nft_tcpflags(r, tcp->flg_cmp, tcp->flg_mask, + int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask, tcp->invflags & XT_TCP_INV_FLAGS); if (ret < 0) @@ -1411,18 +1418,19 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { struct xt_mark_mtinfo1 *mark = (void *)m->data; + uint8_t reg; int op; - add_meta(h, r, NFT_META_MARK); + add_meta(h, r, NFT_META_MARK, ®); if (mark->mask != 0xffffffff) - add_bitwise(r, (uint8_t *)&mark->mask, sizeof(uint32_t)); + add_bitwise(h, r, (uint8_t *)&mark->mask, sizeof(uint32_t), reg, ®); if (mark->invert) op = NFT_CMP_NEQ; else op = NFT_CMP_EQ; - add_cmp_u32(r, mark->mark, op); + add_cmp_u32(r, mark->mark, op, reg); return 0; } -- cgit v1.2.3 From 1dcfb81e02df3ed06b617bd588431813fab6af38 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 Apr 2022 22:19:21 +0200 Subject: nft: split gen_payload() to allocate register and initialize expression Add __gen_payload(), in preparation for the dynamic register allocation. Signed-off-by: Pablo Neira Ayuso --- iptables/nft.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index bdfef024..07653ee1 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1090,20 +1090,30 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table, } static struct nftnl_expr * -gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len, - uint8_t *dreg) +__gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint8_t reg) { struct nftnl_expr *e = nftnl_expr_alloc("payload"); - uint8_t reg; if (!e) return NULL; - reg = NFT_REG_1; nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, reg); + + return e; +} + +static struct nftnl_expr * +gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len, + uint8_t *dreg) +{ + struct nftnl_expr *e; + uint8_t reg; + + reg = NFT_REG_1; + e = __gen_payload(base, offset, len, reg); *dreg = reg; return e; -- cgit v1.2.3 From adbfec0b3e3275ea5e7c933b630756cf01a4f8c6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2022 18:00:14 +0200 Subject: extensions: MARK: Drop extra newline at end of help Fixes: f4b737fb0c52a ("libxt_MARK r2") Signed-off-by: Phil Sutter --- extensions/libxt_MARK.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index b765af6c..1536563d 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -77,8 +77,7 @@ static void mark_tg_help(void) " --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n" " --and-mark bits Binary AND the nfmark with bits\n" " --or-mark bits Binary OR the nfmark with bits\n" -" --xor-mark bits Binary XOR the nfmark with bits\n" -"\n"); +" --xor-mark bits Binary XOR the nfmark with bits\n"); } static void MARK_parse_v0(struct xt_option_call *cb) -- cgit v1.2.3 From 8ff84eaf987d74603a88b02632bd00187defcf8d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2022 18:07:38 +0200 Subject: xshared: Move arp_opcodes into shared space It will be referenced by xtables_printhelp() if printing for arptables and therefore must be present in legacy as well even if unused. Signed-off-by: Phil Sutter --- extensions/libarpt_mangle.c | 1 - iptables/nft-arp.c | 22 ++++------------------ iptables/nft-arp.h | 7 ------- iptables/xshared.c | 14 ++++++++++++++ iptables/xshared.h | 3 +++ iptables/xtables-arp.c | 1 - iptables/xtables-monitor.c | 1 - iptables/xtables.c | 1 - 8 files changed, 21 insertions(+), 29 deletions(-) delete mode 100644 iptables/nft-arp.h diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c index a2378a8b..765edf34 100644 --- a/extensions/libarpt_mangle.c +++ b/extensions/libarpt_mangle.c @@ -13,7 +13,6 @@ #include #include #include "iptables/nft.h" -#include "iptables/nft-arp.h" static void arpmangle_print_help(void) { diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 65bd965e..e6e4d2d8 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -25,22 +25,8 @@ #include #include "nft-shared.h" -#include "nft-arp.h" #include "nft.h" - -/* a few names */ -char *arp_opcodes[] = -{ - "Request", - "Reply", - "Request_Reverse", - "Reply_Reverse", - "DRARP_Request", - "DRARP_Reply", - "DRARP_Error", - "InARP_Request", - "ARP_NAK", -}; +#include "xshared.h" static bool need_devaddr(struct arpt_devaddr_info *info) { @@ -429,7 +415,7 @@ after_devdst: printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP ? "! " : ""); - if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC)) + if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC)) printf("--opcode %s", arp_opcodes[tmp-1]); else printf("--opcode %d", tmp); @@ -660,11 +646,11 @@ static void nft_arp_post_parse(int command, &cs->arp.arp.arpop_mask, 10)) { int i; - for (i = 0; i < NUMOPCODES; i++) + for (i = 0; i < ARP_NUMOPCODES; i++) if (!strcasecmp(arp_opcodes[i], args->arp_opcode)) break; - if (i == NUMOPCODES) + if (i == ARP_NUMOPCODES) xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); cs->arp.arp.arpop = htons(i+1); diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h deleted file mode 100644 index 3411fc3d..00000000 --- a/iptables/nft-arp.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _NFT_ARP_H_ -#define _NFT_ARP_H_ - -extern char *arp_opcodes[]; -#define NUMOPCODES 9 - -#endif diff --git a/iptables/xshared.c b/iptables/xshared.c index 00828c8a..674b49cb 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -20,6 +20,20 @@ #include #include "xshared.h" +/* a few arp opcode names */ +char *arp_opcodes[] = +{ + "Request", + "Reply", + "Request_Reverse", + "Reply_Reverse", + "DRARP_Request", + "DRARP_Reply", + "DRARP_Error", + "InARP_Request", + "ARP_NAK", +}; + /* * Print out any special helps. A user might like to be able to add a --help * to the commandline, and see expected results. So we call help for all diff --git a/iptables/xshared.h b/iptables/xshared.h index ca761ee7..2fdebc32 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -330,4 +330,7 @@ void ipv4_post_parse(int command, struct iptables_command_state *cs, void ipv6_post_parse(int command, struct iptables_command_state *cs, struct xtables_args *args); +extern char *arp_opcodes[]; +#define ARP_NUMOPCODES 9 + #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 68514297..f1a128fc 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -37,7 +37,6 @@ #include "xshared.h" #include "nft.h" -#include "nft-arp.h" static struct option original_opts[] = { { "append", 1, 0, 'A' }, diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 8a04f4d1..905bb7fe 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -37,7 +37,6 @@ #include "iptables.h" /* for xtables_globals */ #include "xtables-multi.h" #include "nft.h" -#include "nft-arp.h" struct cb_arg { uint32_t nfproto; diff --git a/iptables/xtables.c b/iptables/xtables.c index c44b39ac..c65c3fce 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -42,7 +42,6 @@ #include #include "xshared.h" #include "nft-shared.h" -#include "nft-arp.h" #include "nft.h" static struct option original_opts[] = { -- cgit v1.2.3 From 3b8a6a6fa870c5ed4a2c533fcec9524bc98e5709 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2022 18:13:12 +0200 Subject: xshared: Extend xtables_printhelp() for arptables The function checks afinfo->family already to cover ip6tables specifics, doing the same for arptables does not make things much worse. This changes arptables-nft help output slightly: * List possible negations extrapositioned, which is preferred anyway (arptables-nft supports both) * List --out-interface option at lexically sorted position * Print --wait option, it's ignored just like with iptables * Restore default target option printing as with legacy arptables (not sure if arptables-nft ever did this) by explicitly loading them. While being at it, add --set-counters short option '-c' to help output for ip(6)tables. This effectively removes the need for (and all users of) xtables_global's 'print_help' callback, thus effectively reverts commit fe83b12fc910e ("libxtables: Introduce xtables_globals print_help callback") which broke libxtables' ABI compatibility. Signed-off-by: Phil Sutter --- include/xtables.h | 1 - iptables/ip6tables.c | 1 - iptables/iptables.c | 1 - iptables/xshared.c | 53 ++++++++++++++++++++----- iptables/xshared.h | 1 - iptables/xtables-arp.c | 104 ------------------------------------------------- iptables/xtables.c | 1 - 7 files changed, 43 insertions(+), 119 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index 84369dac..a93e8f6e 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -425,7 +425,6 @@ struct xtables_globals struct option *opts; void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); int (*compat_rev)(const char *name, uint8_t rev, int opt); - void (*print_help)(const struct xtables_rule_match *m); }; #define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false} diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index f4796b89..5806a13c 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -93,7 +93,6 @@ struct xtables_globals ip6tables_globals = { .optstring = OPTSTRING_COMMON "R:S::W::" "46bg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, - .print_help = xtables_printhelp, }; /* diff --git a/iptables/iptables.c b/iptables/iptables.c index ccebb1a6..edde604c 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -90,7 +90,6 @@ struct xtables_globals iptables_globals = { .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, - .print_help = xtables_printhelp, }; /* diff --git a/iptables/xshared.c b/iptables/xshared.c index 674b49cb..e959f203 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1156,7 +1156,7 @@ int print_match_save(const struct xt_entry_match *e, const void *ip) return 0; } -void +static void xtables_printhelp(const struct xtables_rule_match *matches) { const char *prog_name = xt_params->program_name; @@ -1203,23 +1203,40 @@ xtables_printhelp(const struct xtables_rule_match *matches) " Change policy on chain to target\n" " --rename-chain\n" " -E old-chain new-chain\n" -" Change chain name, (moving any references)\n"); +" Change chain name, (moving any references)\n" +"\n" +"Options:\n"); - printf( -"Options:\n" + if (afinfo->family == NFPROTO_ARP) { + printf( +"[!] --source-ip -s address[/mask]\n" +" source specification\n" +"[!] --destination-ip -d address[/mask]\n" +" destination specification\n" +"[!] --source-mac address[/mask]\n" +"[!] --destination-mac address[/mask]\n" +" --h-length -l length[/mask] hardware length (nr of bytes)\n" +" --opcode code[/mask] operation code (2 bytes)\n" +" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n" +" --proto-type type[/mask] protocol type (2 bytes)\n"); + } else { + printf( " --ipv4 -4 %s (line is ignored by ip6tables-restore)\n" " --ipv6 -6 %s (line is ignored by iptables-restore)\n" "[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" "[!] --source -s address[/mask][...]\n" " source specification\n" "[!] --destination -d address[/mask][...]\n" -" destination specification\n" +" destination specification\n", + afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error", + afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing"); + } + + printf( "[!] --in-interface -i input name[+]\n" " network interface name ([+] for wildcard)\n" " --jump -j target\n" -" target for rule (may load target extension)\n", - afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error", - afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing"); +" target for rule (may load target extension)\n"); if (0 #ifdef IPT_F_GOTO @@ -1250,9 +1267,25 @@ xtables_printhelp(const struct xtables_rule_match *matches) printf( " --modprobe= 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"); + if (afinfo->family == NFPROTO_ARP) { + int i; + + printf(" opcode strings: \n"); + for (i = 0; i < ARP_NUMOPCODES; i++) + printf(" %d = %s\n", i + 1, arp_opcodes[i]); + printf( + " hardware type string: 1 = Ethernet\n" + " protocol type string: 0x800 = IPv4\n"); + + xtables_find_target("standard", XTF_TRY_LOAD); + xtables_find_target("mangle", XTF_TRY_LOAD); + xtables_find_target("CLASSIFY", XTF_TRY_LOAD); + xtables_find_target("MARK", XTF_TRY_LOAD); + } + print_extension_helps(xtables_targets, matches); } @@ -1475,7 +1508,7 @@ void do_parse(int argc, char *argv[], xtables_find_match(cs->protocol, XTF_TRY_LOAD, &cs->matches); - xt_params->print_help(cs->matches); + xtables_printhelp(cs->matches); exit(0); /* diff --git a/iptables/xshared.h b/iptables/xshared.h index 2fdebc32..e69da735 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -258,7 +258,6 @@ void save_rule_details(const char *iniface, unsigned const char *iniface_mask, int print_match_save(const struct xt_entry_match *e, const void *ip); -void xtables_printhelp(const struct xtables_rule_match *matches); void exit_tryhelp(int status, int line) __attribute__((noreturn)); struct addr_mask { diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index f1a128fc..bf7d44e7 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -83,118 +83,14 @@ static struct option original_opts[] = { #define opts xt_params->opts -static void printhelp(const struct xtables_rule_match *m); struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, .compat_rev = nft_compatible_revision, - .print_help = printhelp, }; -static void -printhelp(const struct xtables_rule_match *m) -{ - struct xtables_target *t = NULL; - int i; - - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - arptables_globals.program_name, - arptables_globals.program_version, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name, - arptables_globals.program_name); - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --source-ip -s [!] address[/mask]\n" -" source specification\n" -" --destination-ip -d [!] address[/mask]\n" -" destination specification\n" -" --source-mac [!] address[/mask]\n" -" --destination-mac [!] address[/mask]\n" -" --h-length -l length[/mask] hardware length (nr of bytes)\n" -" --opcode code[/mask] operation code (2 bytes)\n" -" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n" -" --proto-type type[/mask] protocol type (2 bytes)\n" -" --in-interface -i [!] input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --out-interface -o [!] output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -" --modprobe= try to insert modules using this command\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, arp_opcodes[i]); - printf( -" hardware type string: 1 = Ethernet\n" -" protocol type string: 0x800 = IPv4\n"); - - /* Print out any special helps. A user might like to be able - to add a --help to the commandline, and see expected - results. So we call help for all matches & targets */ - for (t = xtables_targets; t; t = t->next) { - if (strcmp(t->name, "CLASSIFY") && strcmp(t->name, "mangle")) - continue; - printf("\n"); - t->help(); - } -} - int nft_init_arp(struct nft_handle *h, const char *pname) { arptables_globals.program_name = pname; diff --git a/iptables/xtables.c b/iptables/xtables.c index c65c3fce..41b6eb48 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -91,7 +91,6 @@ struct xtables_globals xtables_globals = { .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = nft_compatible_revision, - .print_help = xtables_printhelp, }; /* -- cgit v1.2.3 From fd64a5871b671a66f1ba6d6e3aa83ed24d92c099 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2022 23:48:50 +0200 Subject: libxtables: Drop xtables_globals 'optstring' field Define the different optstrings in xshared.h instead, they are not relevant for other libxtables users. This is a partial revert of commit 65b150ae382a8 ("xshared: Store optstring in xtables_globals") to avoid breaking libxtables' ABI compatibility. Signed-off-by: Phil Sutter --- include/xtables.h | 1 - iptables/ip6tables.c | 1 - iptables/iptables.c | 1 - iptables/xshared.c | 17 ++++++++++++++++- iptables/xshared.h | 3 +++ iptables/xtables-arp.c | 1 - iptables/xtables-eb.c | 3 +-- iptables/xtables.c | 1 - 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index a93e8f6e..8c1065bc 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -420,7 +420,6 @@ struct xtables_globals { unsigned int option_offset; const char *program_name, *program_version; - const char *optstring; struct option *orig_opts; struct option *opts; void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 5806a13c..75984cc1 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -90,7 +90,6 @@ static struct option original_opts[] = { struct xtables_globals ip6tables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", - .optstring = OPTSTRING_COMMON "R:S::W::" "46bg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, }; diff --git a/iptables/iptables.c b/iptables/iptables.c index edde604c..e5207ba1 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -87,7 +87,6 @@ static struct option original_opts[] = { struct xtables_globals iptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (legacy)", - .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = xtables_compatible_revision, }; diff --git a/iptables/xshared.c b/iptables/xshared.c index e959f203..fae5ddd5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1340,6 +1340,20 @@ static void check_inverse(struct xtables_args *args, const char option[], } } +static const char *optstring_lookup(int family) +{ + switch (family) { + case AF_INET: + case AF_INET6: + return IPT_OPTSTRING; + case NFPROTO_ARP: + return ARPT_OPTSTRING; + case NFPROTO_BRIDGE: + return EBT_OPTSTRING; + } + return ""; +} + void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) @@ -1370,7 +1384,8 @@ void do_parse(int argc, char *argv[], opterr = 0; xt_params->opts = xt_params->orig_opts; - while ((cs->c = getopt_long(argc, argv, xt_params->optstring, + while ((cs->c = getopt_long(argc, argv, + optstring_lookup(afinfo->family), xt_params->opts, NULL)) != -1) { switch (cs->c) { /* diff --git a/iptables/xshared.h b/iptables/xshared.h index e69da735..14568bb0 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -68,6 +68,9 @@ struct xtables_rule_match; struct xtables_target; #define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:VX::Z::" "c:d:i:j:o:p:s:t:" +#define IPT_OPTSTRING OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x" +#define ARPT_OPTSTRING OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */ +#define EBT_OPTSTRING OPTSTRING_COMMON "hv" /* define invflags which won't collide with IPT ones */ #define IPT_INV_SRCDEVADDR 0x0080 diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index bf7d44e7..71518a9c 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -86,7 +86,6 @@ static struct option original_opts[] = { struct xtables_globals arptables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", - .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */, .orig_opts = original_opts, .compat_rev = nft_compatible_revision, }; diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index a7bfb9c5..3d15063e 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -220,7 +220,6 @@ struct option ebt_original_options[] = struct xtables_globals ebtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", - .optstring = OPTSTRING_COMMON "hv", .orig_opts = ebt_original_options, .compat_rev = nft_compatible_revision, }; @@ -734,7 +733,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, opterr = false; /* Getopt saves the day */ - while ((c = getopt_long(argc, argv, xt_params->optstring, + while ((c = getopt_long(argc, argv, EBT_OPTSTRING, opts, NULL)) != -1) { cs.c = c; switch (c) { diff --git a/iptables/xtables.c b/iptables/xtables.c index 41b6eb48..70924176 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -88,7 +88,6 @@ static struct option original_opts[] = { struct xtables_globals xtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", - .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x", .orig_opts = original_opts, .compat_rev = nft_compatible_revision, }; -- cgit v1.2.3 From a7c2b7289cd31455b854fee7d5c735c6270518a3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 6 May 2022 00:11:47 +0200 Subject: libxtables: Revert change to struct xtables_pprot While protocol values may exceed eight bits, the data structure is indeed used only to store the static list of name/value pairs for faster lookups. None of those has such a value and if one is added in future, the compiler will complain about it. So restore the old field type to retain binary compatibility. Fixes: 556f704458cdb ("Use proto_to_name() from xshared in more places") Signed-off-by: Phil Sutter --- include/xtables.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xtables.h b/include/xtables.h index 8c1065bc..c2694b7b 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -395,7 +395,7 @@ struct xtables_rule_match { */ struct xtables_pprot { const char *name; - uint16_t num; + uint8_t num; }; enum xtables_tryload { -- cgit v1.2.3 From 0a53825946892bb22605fa2d9381ffa46f73f5c2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 14 Apr 2022 17:44:08 +0200 Subject: extensions: DNAT: Merge core printing functions Have a versatile __NAT_print() function providing enough flexibility for DNAT and REDIRECT, IPv4 and IPv6 and 'print' and 'save' output. Then define macros to simplify calling it. As a side effect, this fixes ip6tables DNAT revision 1 print output. Fixes: 14d77c8aa29a7 ("extensions: Merge IPv4 and IPv6 DNAT targets") Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.c | 58 +++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 5ac8018c..5696d31f 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -312,31 +312,40 @@ static char *sprint_range(const struct nf_nat_range2 *r, int family) return buf; } -static void __DNAT_print(const struct nf_nat_range2 *r, bool save, int family) +static void __NAT_print(const struct nf_nat_range2 *r, int family, + const char *rangeopt, const char *flag_pfx, + bool skip_colon) { - const char *dashdash = save ? "--" : ""; + char *range_str = sprint_range(r, family); - printf(" %s%s", save ? "--to-destination " : "to:", - sprint_range(r, family)); + if (strlen(range_str)) { + if (range_str[0] == ':' && skip_colon) + range_str++; + printf(" %s%s", rangeopt, range_str); + } if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" %srandom", dashdash); + printf(" %srandom", flag_pfx); if (r->flags & NF_NAT_RANGE_PERSISTENT) - printf(" %spersistent", dashdash); + printf(" %spersistent", flag_pfx); } +#define __DNAT_print(r, family) __NAT_print(r, family, "to:", "", false) +#define __DNAT_save(r, family) __NAT_print(r, family, "--to-destination ", "--", false) +#define __REDIRECT_print(r) __NAT_print(r, AF_INET, "redir ports ", "", true) +#define __REDIRECT_save(r) __NAT_print(r, AF_INET, "--to-ports ", "--", true) static void DNAT_print(const void *ip, const struct xt_entry_target *target, int numeric) { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __DNAT_print(&range, false, AF_INET); + __DNAT_print(&range, AF_INET); } static void DNAT_save(const void *ip, const struct xt_entry_target *target) { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __DNAT_print(&range, true, AF_INET); + __DNAT_save(&range, AF_INET); } static int @@ -387,12 +396,12 @@ static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, int numeric) { - __DNAT_print((const void *)target->data, false, AF_INET); + __DNAT_print((const void *)target->data, AF_INET); } static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) { - __DNAT_print((const void *)target->data, true, AF_INET); + __DNAT_save((const void *)target->data, AF_INET); } static int DNAT_xlate_v2(struct xt_xlate *xl, @@ -429,7 +438,7 @@ static void DNAT_print6(const void *ip, const struct xt_entry_target *target, struct nf_nat_range2 range = {}; memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_print(&range, true, AF_INET6); + __DNAT_print(&range, AF_INET6); } static void DNAT_save6(const void *ip, const struct xt_entry_target *target) @@ -437,7 +446,7 @@ static void DNAT_save6(const void *ip, const struct xt_entry_target *target) struct nf_nat_range2 range = {}; memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_print(&range, true, AF_INET6); + __DNAT_save(&range, AF_INET6); } static int DNAT_xlate6(struct xt_xlate *xl, @@ -460,12 +469,12 @@ static void DNAT_parse6_v2(struct xt_option_call *cb) static void DNAT_print6_v2(const void *ip, const struct xt_entry_target *target, int numeric) { - __DNAT_print((const void *)target->data, true, AF_INET6); + __DNAT_print((const void *)target->data, AF_INET6); } static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target) { - __DNAT_print((const void *)target->data, true, AF_INET6); + __DNAT_save((const void *)target->data, AF_INET6); } static int DNAT_xlate6_v2(struct xt_xlate *xl, @@ -474,19 +483,6 @@ static int DNAT_xlate6_v2(struct xt_xlate *xl, return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); } -static void __REDIRECT_print(const struct nf_nat_range2 *range, bool save) -{ - char *range_str = sprint_range(range, AF_INET); - const char *dashdash = save ? "--" : ""; - - if (strlen(range_str)) - /* range_str starts with colon, skip over them */ - printf(" %s %s", save ? "--to-ports" : "redir ports", - range_str + 1); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" %srandom", dashdash); -} - static int __REDIRECT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *range) { @@ -506,14 +502,14 @@ static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __REDIRECT_print(&range, false); + __REDIRECT_print(&range); } static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) { struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - __REDIRECT_print(&range, true); + __REDIRECT_save(&range); } static int REDIRECT_xlate(struct xt_xlate *xl, @@ -531,7 +527,7 @@ static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target struct nf_nat_range2 range = {}; memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_print(&range, false); + __REDIRECT_print(&range); } static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) @@ -539,7 +535,7 @@ static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) struct nf_nat_range2 range = {}; memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_print(&range, true); + __REDIRECT_save(&range); } static int REDIRECT_xlate6(struct xt_xlate *xl, -- cgit v1.2.3 From 404f304d00e69dcdfdb83537e8c11b8c253e415e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 16 Apr 2022 14:21:51 +0200 Subject: man: *NAT: Review --random* option descriptions Stating the option again in the first (single?) sentence is pointless. Get rid of that initial half-sentence in MASQUERADE options and unify the texts a bit. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.man | 4 +--- extensions/libxt_MASQUERADE.man | 10 ++-------- extensions/libxt_REDIRECT.man | 4 +--- extensions/libxt_SNAT.man | 8 ++------ 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man index 12d334af..af9a3f06 100644 --- a/extensions/libxt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -25,9 +25,7 @@ For a single port or \fIbaseport\fP, a service name as listed in \fB/etc/services\fP may be used. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.22). +Randomize source port mapping (kernel >= 2.6.22). .TP \fB\-\-persistent\fP Gives a client the same source-/destination-address for each connection. diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man index 7746f473..26d91ddb 100644 --- a/extensions/libxt_MASQUERADE.man +++ b/extensions/libxt_MASQUERADE.man @@ -20,16 +20,10 @@ if the rule also specifies one of the following protocols: \fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. .TP \fB\-\-random\fP -Randomize source port mapping -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.21). +Randomize source port mapping (kernel >= 2.6.21). Since kernel 5.0, \fB\-\-random\fP is identical to \fB\-\-random-fully\fP. .TP \fB\-\-random-fully\fP -Full randomize source port mapping -If option -\fB\-\-random-fully\fP -is used then port mapping will be fully randomized (kernel >= 3.13). +Fully randomize source port mapping (kernel >= 3.13). .TP IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_REDIRECT.man b/extensions/libxt_REDIRECT.man index 10305597..1cbdb9ba 100644 --- a/extensions/libxt_REDIRECT.man +++ b/extensions/libxt_REDIRECT.man @@ -19,8 +19,6 @@ if the rule also specifies one of the following protocols: For a single port, a service name as listed in \fB/etc/services\fP may be used. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.22). +Randomize source port mapping (kernel >= 2.6.22). .TP IPv6 support available starting Linux kernels >= 3.7. diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man index 08766447..80a698a6 100644 --- a/extensions/libxt_SNAT.man +++ b/extensions/libxt_SNAT.man @@ -21,14 +21,10 @@ will be mapped to ports below 1024, and other ports will be mapped to 1024 or above. Where possible, no port alteration will occur. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized through a hash-based algorithm (kernel >= 2.6.21). +Randomize source port mapping through a hash-based algorithm (kernel >= 2.6.21). .TP \fB\-\-random-fully\fP -If option -\fB\-\-random-fully\fP -is used then port mapping will be fully randomized through a PRNG (kernel >= 3.14). +Fully randomize source port mapping through a PRNG (kernel >= 3.14). .TP \fB\-\-persistent\fP Gives a client the same source-/destination-address for each connection. -- cgit v1.2.3 From ce9195c6e2fa6c6daa3c34b94353a539237b3809 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 24 Mar 2022 11:06:24 +0100 Subject: extensions: LOG: Document --log-macdecode in man page Help text already contains it, so no update needed there. Fixes: 127647892c7ca ("extensions: libipt_LOG/libip6t_LOG: support macdecode option") Signed-off-by: Phil Sutter --- extensions/libxt_LOG.man | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man index 354edf4c..1d5071ba 100644 --- a/extensions/libxt_LOG.man +++ b/extensions/libxt_LOG.man @@ -30,3 +30,6 @@ Log options from the IP/IPv6 packet header. .TP \fB\-\-log\-uid\fP Log the userid of the process which generated the packet. +.TP +\fB\-\-log\-macdecode\fP +Log MAC addresses and protocol. -- cgit v1.2.3 From 8468fd4f7c85c21ab375402bc80d0188412b6cbf Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 4 May 2022 11:19:16 +0200 Subject: nft: Fix EPERM handling for extensions without rev 0 Treating revision 0 as compatible in EPERM case works fine as long as there is a revision 0 of that extension defined in DSO. Fix the code for others: Extend the EPERM handling to all revisions and keep the existing warning for revision 0. Fixes: 17534cb18ed0a ("Improve error messages for unsupported extensions") Signed-off-by: Phil Sutter --- iptables/nft.c | 11 +++++++---- iptables/tests/shell/testcases/iptables/0008-unprivileged_0 | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 07653ee1..ec79f2bc 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3555,15 +3555,18 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt) err: mnl_socket_close(nl); - /* pretend revision 0 is valid - + /* ignore EPERM and errors for revision 0 - * this is required for printing extension help texts as user, also * helps error messaging on unavailable kernel extension */ - if (ret < 0 && rev == 0) { - if (errno != EPERM) + if (ret < 0) { + if (errno == EPERM) + return 1; + if (rev == 0) { fprintf(stderr, "Warning: Extension %s revision 0 not supported, missing kernel module?\n", name); - return 1; + return 1; + } } return ret < 0 ? 0 : 1; diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 index 43e3bc87..983531fe 100755 --- a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 +++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 @@ -35,6 +35,12 @@ let "rc+=$?" grep_or_rc "DNAT target options:" <<< "$out" let "rc+=$?" +# TEE has no revision 0 +out=$(run $XT_MULTI iptables -j TEE --help) +let "rc+=$?" +grep_or_rc "TEE target options:" <<< "$out" +let "rc+=$?" + out=$(run $XT_MULTI iptables -p tcp -j DNAT --help) let "rc+=$?" grep_or_rc "tcp match options:" <<< "$out" -- cgit v1.2.3 From fa0ccdbdbec467ee6a562d5de38eaaefa1016ad7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 13 May 2022 15:26:12 +0200 Subject: configure: bump version for 1.8.8 release Signed-off-by: Pablo Neira Ayuso --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 86c67194..071afaf1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ -AC_INIT([iptables], [1.8.7]) +AC_INIT([iptables], [1.8.8]) # See libtool.info "Libtool's versioning system" -libxtables_vcurrent=17 -libxtables_vage=5 +libxtables_vcurrent=18 +libxtables_vage=6 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.2.3 From b72eb12ea5a61df0655ad99d5048994e916be83a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 13 May 2022 16:51:58 +0200 Subject: xshared: Fix build for -Werror=format-security Gcc complains about the omitted format string. Signed-off-by: Phil Sutter --- iptables/xshared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index fae5ddd5..a8512d38 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1307,7 +1307,7 @@ static void check_empty_interface(struct xtables_args *args, const char *arg) return; if (args->family != NFPROTO_ARP) - xtables_error(PARAMETER_PROBLEM, msg); + xtables_error(PARAMETER_PROBLEM, "%s", msg); fprintf(stderr, "%s", msg); } -- cgit v1.2.3 From f319389525b066b7dc6d389c88f16a0df3b8f189 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Mon, 16 May 2022 18:16:41 +0200 Subject: treewide: use uint* instead of u_int* Gcc complains about missing types. Some commits introduced u_int* instead of uint*. Use uint treewide. Fixes errors in the form of: In file included from xtables-legacy-multi.c:5: xshared.h:83:56: error: unknown type name 'u_int16_t'; did you mean 'uint16_t'? 83 | set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, | ^~~~~~~~~ | uint16_t make[6]: *** [Makefile:712: xtables_legacy_multi-xtables-legacy-multi.o] Error 1 Avoid libipq API breakage by adjusting libipq.h include accordingly. For arpt_mangle.h kernel uAPI header, apply same change as in kernel commit e91ded8db5747 ("uapi: netfilter_arp: use __u8 instead of u_int8_t"). Signed-off-by: Nick Hainke Signed-off-by: Phil Sutter --- extensions/libxt_conntrack.c | 2 +- include/libipq/libipq.h | 8 ++++---- include/libiptc/libxtc.h | 2 +- include/linux/netfilter_arp/arpt_mangle.h | 2 +- iptables/xshared.c | 2 +- iptables/xshared.h | 2 +- libipq/ipq_create_handle.3 | 2 +- libipq/ipq_set_mode.3 | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 64018ce1..234085c5 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -778,7 +778,7 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, static void conntrack_dump_ports(const char *prefix, const char *opt, - u_int16_t port_low, u_int16_t port_high) + uint16_t port_low, uint16_t port_high) { if (port_high == 0 || port_low == port_high) printf(" %s%s %u", prefix, opt, port_low); diff --git a/include/libipq/libipq.h b/include/libipq/libipq.h index 3cd13292..dd0cb205 100644 --- a/include/libipq/libipq.h +++ b/include/libipq/libipq.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,19 +48,19 @@ typedef unsigned long ipq_id_t; struct ipq_handle { int fd; - u_int8_t blocking; + uint8_t blocking; struct sockaddr_nl local; struct sockaddr_nl peer; }; -struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol); +struct ipq_handle *ipq_create_handle(uint32_t flags, uint32_t protocol); int ipq_destroy_handle(struct ipq_handle *h); ssize_t ipq_read(const struct ipq_handle *h, unsigned char *buf, size_t len, int timeout); -int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len); +int ipq_set_mode(const struct ipq_handle *h, uint8_t mode, size_t len); ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf); diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h index 37010188..a1d16ef9 100644 --- a/include/libiptc/libxtc.h +++ b/include/libiptc/libxtc.h @@ -10,7 +10,7 @@ extern "C" { #endif #ifndef XT_MIN_ALIGN -/* xt_entry has pointers and u_int64_t's in it, so if you align to +/* xt_entry has pointers and uint64_t's in it, so if you align to it, you'll also align to any crazy matches and targets someone might write */ #define XT_MIN_ALIGN (__alignof__(struct xt_entry)) diff --git a/include/linux/netfilter_arp/arpt_mangle.h b/include/linux/netfilter_arp/arpt_mangle.h index 250f5029..8c2b16a1 100644 --- a/include/linux/netfilter_arp/arpt_mangle.h +++ b/include/linux/netfilter_arp/arpt_mangle.h @@ -13,7 +13,7 @@ struct arpt_mangle union { struct in_addr tgt_ip; } u_t; - u_int8_t flags; + __u8 flags; int target; }; diff --git a/iptables/xshared.c b/iptables/xshared.c index a8512d38..9b5e5b5b 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1025,7 +1025,7 @@ static const int inverse_for_options[NUMBER_OF_OPT] = }; void -set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, +set_option(unsigned int *options, unsigned int option, uint16_t *invflg, bool invert) { if (*options & option) diff --git a/iptables/xshared.h b/iptables/xshared.h index 14568bb0..f8212988 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -80,7 +80,7 @@ struct xtables_target; #define IPT_INV_ARPHRD 0x0800 void -set_option(unsigned int *options, unsigned int option, u_int16_t *invflg, +set_option(unsigned int *options, unsigned int option, uint16_t *invflg, bool invert); /** diff --git a/libipq/ipq_create_handle.3 b/libipq/ipq_create_handle.3 index 11ef95c4..ebe46daa 100644 --- a/libipq/ipq_create_handle.3 +++ b/libipq/ipq_create_handle.3 @@ -24,7 +24,7 @@ ipq_create_handle, ipq_destroy_handle \(em create and destroy libipq handles. .br .B #include .sp -.BI "struct ipq_handle *ipq_create_handle(u_int32_t " flags ", u_int32_t " protocol ");" +.BI "struct ipq_handle *ipq_create_handle(uint32_t " flags ", uint32_t " protocol ");" .br .BI "int ipq_destroy_handle(struct ipq_handle *" h ); .SH DESCRIPTION diff --git a/libipq/ipq_set_mode.3 b/libipq/ipq_set_mode.3 index 0edd3c00..e206886c 100644 --- a/libipq/ipq_set_mode.3 +++ b/libipq/ipq_set_mode.3 @@ -24,7 +24,7 @@ ipq_set_mode \(em set the ip_queue queuing mode .br .B #include .sp -.BI "int ipq_set_mode(const struct ipq_handle *" h ", u_int8_t " mode ", size_t " range ); +.BI "int ipq_set_mode(const struct ipq_handle *" h ", uint8_t " mode ", size_t " range ); .SH DESCRIPTION The .B ipq_set_mode -- cgit v1.2.3 From 0e7cf0ad306cdf95dc3c28d15a254532206a888e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 18 May 2022 16:04:09 +0200 Subject: Revert "fix build for missing ETH_ALEN definition" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c5d9a723b5159a28f547b577711787295a14fd84 as it broke compiling against musl libc. Might be a bug in the latter, but for the time being try to please both by avoiding the include and instead defining ETH_ALEN if unset. While being at it, move netinet/ether.h include up. Fixes: 1bdb5535f561a ("libxtables: Extend MAC address printing/parsing support") Signed-off-by: Phil Sutter Reviewed-by: Maciej Żenczykowski --- libxtables/xtables.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 96fd783a..0638f927 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,6 @@ #include #include /* INT_MAX in ip_tables.h/ip6_tables.h */ -#include /* ETH_ALEN */ #include #include #include @@ -72,6 +72,10 @@ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + /* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the * current line of the input file, in order to give a more precise error * message. ip6?tables itself doesn't need this, so it is initialized to the @@ -2245,8 +2249,6 @@ void xtables_print_num(uint64_t number, unsigned int format) printf(FMT("%4lluT ","%lluT "), (unsigned long long)number); } -#include - static const unsigned char mac_type_unicast[ETH_ALEN] = {}; static const unsigned char msk_type_unicast[ETH_ALEN] = {1}; static const unsigned char mac_type_multicast[ETH_ALEN] = {1}; -- cgit v1.2.3 From 0ebf52fc951b2a4d98a166afb34af4f364bbeece Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Wed, 25 May 2022 16:26:13 +0100 Subject: build: Fix error during out of tree build Fixes the following error: ../../libxtables/xtables.c:52:10: fatal error: libiptc/linux_list.h: No such file or directory 52 | #include Fixes: f58b0d7406451 ("libxtables: Implement notargets hash table") Signed-off-by: Ben Brown Signed-off-by: Phil Sutter --- libxtables/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libxtables/Makefile.am b/libxtables/Makefile.am index 8ff6b0ca..3bfded85 100644 --- a/libxtables/Makefile.am +++ b/libxtables/Makefile.am @@ -1,7 +1,7 @@ # -*- Makefile -*- AM_CFLAGS = ${regular_CFLAGS} -AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables ${kinclude_CPPFLAGS} +AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables -I${top_srcdir} ${kinclude_CPPFLAGS} lib_LTLIBRARIES = libxtables.la libxtables_la_SOURCES = xtables.c xtoptions.c getethertype.c -- cgit v1.2.3 From 0416ae5dea134b33e22c97e68b64010d679debe1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 2 Jun 2022 13:44:45 +0200 Subject: tests: shell: Check overhead in iptables-save and -restore Some repeated calls have been reduced recently, assert this in a test evaluating strace output. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/ipt-save/0007-overhead_0 | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 iptables/tests/shell/testcases/ipt-save/0007-overhead_0 diff --git a/iptables/tests/shell/testcases/ipt-save/0007-overhead_0 b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0 new file mode 100755 index 00000000..b86d71f2 --- /dev/null +++ b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0 @@ -0,0 +1,37 @@ +#!/bin/bash + +# Test recent performance improvements in iptables-save due to reduced +# overhead. + +strace --version >/dev/null || { echo "skip for missing strace"; exit 0; } + +RULESET=$( + echo "*filter" + for ((i = 0; i < 100; i++)); do + echo ":mychain$i -" + echo "-A FORWARD -p tcp --dport 22 -j mychain$i" + done + echo "COMMIT" +) + +RESTORE_STRACE=$(strace $XT_MULTI iptables-restore <<< "$RULESET" 2>&1 >/dev/null) +SAVE_STRACE=$(strace $XT_MULTI iptables-save 2>&1 >/dev/null) + +do_grep() { # (name, threshold, pattern) + local cnt=$(grep -c "$3") + [[ $cnt -le $2 ]] && return 0 + echo "ERROR: Too many $3 lookups for $1: $cnt > $2" + exit 1 +} + +# iptables prefers hard-coded protocol names instead of looking them up first + +do_grep "$XT_MULTI iptables-restore" 0 /etc/protocols <<< "$RESTORE_STRACE" +do_grep "$XT_MULTI iptables-save" 0 /etc/protocols <<< "$SAVE_STRACE" + +# iptables-nft-save pointlessly checked whether chain jumps are targets + +do_grep "$XT_MULTI iptables-restore" 10 libxt_ <<< "$RESTORE_STRACE" +do_grep "$XT_MULTI iptables-save" 10 libxt_ <<< "$SAVE_STRACE" + +exit 0 -- cgit v1.2.3 From ef108943f69a6e20533d58823740d3f0534ea8ec Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 1 Jun 2022 19:15:06 +0200 Subject: libxtables: Unexport init_extensions*() declarations The functions are used for static builds to initialize extensions after libxtables init. Regular library users should not need them, but the empty declarations introduced in #else case (and therefore present in user's env) may clash with existing symbol names. Avoid problems and guard the whole block declaring the function prototypes and mangling extensions' _init functions by XTABLES_INTERNAL. Reported-by: Nick Hainke Fixes: 6c689b639cf8e ("Simplify static build extension loading") Signed-off-by: Phil Sutter --- include/xtables.h | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index c2694b7b..f1937f3e 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -585,27 +585,6 @@ static inline void xtables_print_mark_mask(unsigned int mark, xtables_print_val_mask(mark, mask, NULL); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) -# ifdef _INIT -# undef _init -# define _init _INIT -# endif - extern void init_extensions(void); - extern void init_extensions4(void); - extern void init_extensions6(void); - extern void init_extensionsa(void); - extern void init_extensionsb(void); -#else -# define _init __attribute__((constructor)) _INIT -# define EMPTY_FUNC_DEF(x) static inline void x(void) {} - EMPTY_FUNC_DEF(init_extensions) - EMPTY_FUNC_DEF(init_extensions4) - EMPTY_FUNC_DEF(init_extensions6) - EMPTY_FUNC_DEF(init_extensionsa) - EMPTY_FUNC_DEF(init_extensionsb) -# undef EMPTY_FUNC_DEF -#endif - extern const struct xtables_pprot xtables_chain_protos[]; extern uint16_t xtables_parse_protocol(const char *s); @@ -663,9 +642,30 @@ void xtables_announce_chain(const char *name); # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) # endif +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) +# ifdef _INIT +# undef _init +# define _init _INIT +# endif + extern void init_extensions(void); + extern void init_extensions4(void); + extern void init_extensions6(void); + extern void init_extensionsa(void); + extern void init_extensionsb(void); +#else +# define _init __attribute__((constructor)) _INIT +# define EMPTY_FUNC_DEF(x) static inline void x(void) {} + EMPTY_FUNC_DEF(init_extensions) + EMPTY_FUNC_DEF(init_extensions4) + EMPTY_FUNC_DEF(init_extensions6) + EMPTY_FUNC_DEF(init_extensionsa) + EMPTY_FUNC_DEF(init_extensionsb) +# undef EMPTY_FUNC_DEF +#endif + extern void _init(void); -#endif +#endif /* XTABLES_INTERNAL */ #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3 From 24c5b593156de29a49146bcc3497ebb7d8d40ef0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 7 Jun 2022 18:07:00 +0200 Subject: arptables: Support -x/--exact flag Legacy arptables accepts but ignores the flag. Yet there are remains of the functionality in sources, like OPT_EXPANDED define and a print_num() function which acts on FMT_KILOMEGAGIGA flag being set or not. So instead of mimicking legacy behaviour by explicitly ignoring -x flag for arptables, just enable the feature for it. Signed-off-by: Phil Sutter --- iptables/xshared.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/xshared.h b/iptables/xshared.h index f8212988..2498e32d 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -69,7 +69,7 @@ struct xtables_target; #define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:VX::Z::" "c:d:i:j:o:p:s:t:" #define IPT_OPTSTRING OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x" -#define ARPT_OPTSTRING OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */ +#define ARPT_OPTSTRING OPTSTRING_COMMON "R:S::" "h::l:nvx" /* "m:" */ #define EBT_OPTSTRING OPTSTRING_COMMON "hv" /* define invflags which won't collide with IPT ones */ -- cgit v1.2.3 From ef5d0c68261611d72ccecb3ae05c24448fbc91f5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 1 Jun 2022 19:29:28 +0200 Subject: iptables-legacy: Drop redundant include of xtables-multi.h The header is included unconditionally first, so no point in doing it a second time of ENABLE_NFTABLES is defined. Fixes: be70918eab26e ("xtables: rename xt-multi binaries to -nft, -legacy") Signed-off-by: Phil Sutter --- iptables/xtables-legacy-multi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iptables/xtables-legacy-multi.c b/iptables/xtables-legacy-multi.c index 3b7905ff..2c719315 100644 --- a/iptables/xtables-legacy-multi.c +++ b/iptables/xtables-legacy-multi.c @@ -14,10 +14,6 @@ #include "ip6tables-multi.h" #endif -#ifdef ENABLE_NFTABLES -#include "xtables-multi.h" -#endif - static const struct subcommand multi_subcommands[] = { #ifdef ENABLE_IPV4 {"iptables", iptables_main}, -- cgit v1.2.3 From 6de62a9d47624155fa67530bc4a8f0ea647189f6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 1 Jun 2022 19:24:41 +0200 Subject: xshared: Make some functions static With all ip(6)tables variants using the same do_parse() function, quite a bunch of functions are not used outside of xshared.c anymore. Make them static. Signed-off-by: Phil Sutter --- iptables/xshared.c | 30 +++++++++++++++++------------- iptables/xshared.h | 21 --------------------- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 9b5e5b5b..bd4e1022 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -39,8 +39,8 @@ char *arp_opcodes[] = * to the commandline, and see expected results. So we call help for all * specified matches and targets. */ -void print_extension_helps(const struct xtables_target *t, - const struct xtables_rule_match *m) +static void print_extension_helps(const struct xtables_target *t, + const struct xtables_rule_match *m) { for (; t != NULL; t = t->next) { if (t->used) { @@ -129,8 +129,8 @@ static struct xtables_match *load_proto(struct iptables_command_state *cs) cs->options & OPT_NUMERIC, &cs->matches); } -int command_default(struct iptables_command_state *cs, - struct xtables_globals *gl, bool invert) +static int command_default(struct iptables_command_state *cs, + struct xtables_globals *gl, bool invert) { struct xtables_rule_match *matchp; struct xtables_match *m; @@ -789,7 +789,7 @@ void save_iface(char letter, const char *iface, } } -void command_match(struct iptables_command_state *cs, bool invert) +static void command_match(struct iptables_command_state *cs, bool invert) { struct option *opts = xt_params->opts; struct xtables_match *m; @@ -827,7 +827,7 @@ void command_match(struct iptables_command_state *cs, bool invert) xt_params->opts = opts; } -const char *xt_parse_target(const char *targetname) +static const char *xt_parse_target(const char *targetname) { const char *ptr; @@ -889,7 +889,7 @@ void command_jump(struct iptables_command_state *cs, const char *jumpto) xt_params->opts = opts; } -char cmd2char(int option) +static char cmd2char(int option) { /* cmdflags index corresponds with position of bit in CMD_* values */ static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', @@ -905,8 +905,8 @@ char cmd2char(int option) return cmdflags[i]; } -void add_command(unsigned int *cmd, const int newcmd, - const int othercmds, int invert) +static void add_command(unsigned int *cmd, const int newcmd, + const int othercmds, int invert) { if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag"); @@ -917,7 +917,7 @@ void add_command(unsigned int *cmd, const int newcmd, } /* Can't be zero. */ -int parse_rulenumber(const char *rule) +static int parse_rulenumber(const char *rule) { unsigned int rulenum; @@ -928,6 +928,10 @@ int parse_rulenumber(const char *rule) return rulenum; } +#define NUMBER_OF_OPT ARRAY_SIZE(optflags) +static const char optflags[] += { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 }; + /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to * CMD_LIST and CMD_ZERO only). @@ -957,7 +961,7 @@ static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '}, }; -void generic_opt_check(int command, int options) +static void generic_opt_check(int command, int options) { int i, j, legal = 0; @@ -992,7 +996,7 @@ void generic_opt_check(int command, int options) } } -char opt2char(int option) +static char opt2char(int option) { const char *ptr; @@ -1024,7 +1028,7 @@ static const int inverse_for_options[NUMBER_OF_OPT] = /* 6 */ IPT_INV_PROTO, }; -void +static void set_option(unsigned int *options, unsigned int option, uint16_t *invflg, bool invert) { diff --git a/iptables/xshared.h b/iptables/xshared.h index 2498e32d..1d6b9bf4 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -39,10 +39,6 @@ enum { OPT_P_TYPE = 1 << 17, }; -#define NUMBER_OF_OPT ARRAY_SIZE(optflags) -static const char optflags[] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 }; - enum { CMD_NONE = 0, CMD_INSERT = 1 << 0, @@ -79,10 +75,6 @@ struct xtables_target; #define IPT_INV_ARPOP 0x0400 #define IPT_INV_ARPHRD 0x0800 -void -set_option(unsigned int *options, unsigned int option, uint16_t *invflg, - bool invert); - /** * xtables_afinfo - protocol family dependent information * @kmod: kernel module basename (e.g. "ip_tables") @@ -164,10 +156,6 @@ enum { XT_OPTION_OFFSET_SCALE = 256, }; -extern void print_extension_helps(const struct xtables_target *, - const struct xtables_rule_match *); -extern int command_default(struct iptables_command_state *, - struct xtables_globals *, bool invert); extern int subcmd_main(int, char **, const struct subcommand *); extern void xs_init_target(struct xtables_target *); extern void xs_init_match(struct xtables_match *); @@ -239,19 +227,10 @@ void save_iface(char letter, const char *iface, void print_fragment(unsigned int flags, unsigned int invflags, unsigned int format, bool fake); -void command_match(struct iptables_command_state *cs, bool invert); -const char *xt_parse_target(const char *targetname); void command_jump(struct iptables_command_state *cs, const char *jumpto); -char cmd2char(int option); -void add_command(unsigned int *cmd, const int newcmd, - const int othercmds, int invert); -int parse_rulenumber(const char *rule); void assert_valid_chain_name(const char *chainname); -void generic_opt_check(int command, int options); -char opt2char(int option); - void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, const char *targname, uint8_t proto, uint8_t flags, uint8_t invflags, unsigned int format); -- cgit v1.2.3 From 800f38c973dd1c9608c287eafecffad828e17929 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 20 May 2021 11:59:23 +0200 Subject: Makefile: Add --enable-profiling configure option A little convenience to prepare a build for analysis with gcov/gprof. Signed-off-by: Phil Sutter --- .gitignore | 4 ++++ configure.ac | 10 ++++++++++ extensions/GNUmakefile.in | 2 +- iptables/Makefile.am | 1 + libipq/Makefile.am | 1 + libiptc/Makefile.am | 1 + libxtables/Makefile.am | 1 + utils/Makefile.am | 1 + 8 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e5595264..a206fb48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ *.a +*.gcda +*.gcno +*.gcno.gcov.json.gz +*.gcov *.la *.lo *.so diff --git a/configure.ac b/configure.ac index 071afaf1..ea5d2d49 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,9 @@ AC_ARG_WITH([xt-lock-name], AS_HELP_STRING([--with-xt-lock-name=PATH], [Path to the xtables lock [[/run/xtables.lock]]]), [xt_lock_name="$withval"], [xt_lock_name="/run/xtables.lock"]) +AC_ARG_ENABLE([profiling], + AS_HELP_STRING([--enable-profiling], [build for use of gcov/gprof]), + [enable_profiling="$enableval"], [enable_profiling="no"]) AC_MSG_CHECKING([whether $LD knows -Wl,--no-undefined]) saved_LDFLAGS="$LDFLAGS"; @@ -188,6 +191,11 @@ if [[ -n "$ksourcedir" ]]; then fi; pkgdatadir='${datadir}/xtables'; +if test "x$enable_profiling" = "xyes"; then + regular_CFLAGS+=" -fprofile-arcs -ftest-coverage" + regular_LDFLAGS+=" -lgcov --coverage" +fi + define([EXPAND_VARIABLE], [$2=[$]$1 if test $prefix = 'NONE'; then @@ -205,6 +213,7 @@ eval "$2=[$]$2" AC_SUBST([regular_CFLAGS]) AC_SUBST([regular_CPPFLAGS]) AC_SUBST([noundef_LDFLAGS]) +AC_SUBST([regular_LDFLAGS]) AC_SUBST([kinclude_CPPFLAGS]) AC_SUBST([kbuilddir]) AC_SUBST([ksourcedir]) @@ -250,6 +259,7 @@ Iptables Configuration: nfsynproxy util support: ${enable_nfsynproxy} nftables support: ${enable_nftables} connlabel support: ${enable_connlabel} + profiling support: ${enable_profiling} Build parameters: Put plugins into executable (static): ${enable_static} diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 6dad4e02..3c68f8de 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -24,7 +24,7 @@ kinclude_CPPFLAGS = @kinclude_CPPFLAGS@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${CPPFLAGS} @libnetfilter_conntrack_CFLAGS@ @libnftnl_CFLAGS@ AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ -AM_LDFLAGS = @noundef_LDFLAGS@ +AM_LDFLAGS = @noundef_LDFLAGS@ @regular_LDFLAGS@ ifeq (${V},) AM_LIBTOOL_SILENT = --silent diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 0258264c..23f8352d 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -2,6 +2,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${libmnl_CFLAGS} ${libnftnl_CFLAGS} ${libnetfilter_conntrack_CFLAGS} +AM_LDFLAGS = ${regular_LDFLAGS} BUILT_SOURCES = diff --git a/libipq/Makefile.am b/libipq/Makefile.am index 9e3a2ca6..2cdaf32e 100644 --- a/libipq/Makefile.am +++ b/libipq/Makefile.am @@ -2,6 +2,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include +AM_LDFLAGS = ${regular_LDFLAGS} libipq_la_SOURCES = libipq.c lib_LTLIBRARIES = libipq.la diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am index 464a0696..097842f2 100644 --- a/libiptc/Makefile.am +++ b/libiptc/Makefile.am @@ -2,6 +2,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include ${kinclude_CPPFLAGS} +AM_LDFLAGS = ${regular_LDFLAGS} pkgconfig_DATA = libiptc.pc libip4tc.pc libip6tc.pc diff --git a/libxtables/Makefile.am b/libxtables/Makefile.am index 3bfded85..2f4a12e5 100644 --- a/libxtables/Makefile.am +++ b/libxtables/Makefile.am @@ -2,6 +2,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables -I${top_srcdir} ${kinclude_CPPFLAGS} +AM_LDFLAGS = ${regular_LDFLAGS} lib_LTLIBRARIES = libxtables.la libxtables_la_SOURCES = xtables.c xtoptions.c getethertype.c diff --git a/utils/Makefile.am b/utils/Makefile.am index 42bd9737..327a29e0 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -3,6 +3,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \ -I${top_srcdir}/include ${libnfnetlink_CFLAGS} +AM_LDFLAGS = ${regular_LDFLAGS} sbin_PROGRAMS = pkgdata_DATA = -- cgit v1.2.3 From a219f8d407ee22d69bf74478b6c7331c602b28c6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 20 May 2021 11:40:18 +0200 Subject: tests: shell: Add some more rules to 0002-verbose-output_0 This increases coverage of function print_match() from 0 to 86.6%. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/ip6tables/0002-verbose-output_0 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index 7b0e6468..7624cbab 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -9,12 +9,24 @@ RULE1='-i eth2 -o eth3 -s feed:babe::1 -d feed:babe::2 -j ACCEPT' VOUT1='ACCEPT all opt in eth2 out eth3 feed:babe::1 -> feed:babe::2' RULE2='-i eth2 -o eth3 -s feed:babe::4 -d feed:babe::5 -j ACCEPT' VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5' +RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route' +VOUT3=' ipv6-icmp opt in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' +RULE4='-m dst --dst-len 42 -m rt --rt-type 23' +VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23' +RULE5='-m frag --fragid 1337 -j LOG' +VOUT5='LOG all opt in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -A FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -I FORWARD 2 $RULE2) +diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -A FORWARD $RULE3) +diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -A FORWARD $RULE4) +diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -A FORWARD $RULE5) diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -C FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -C FORWARD $RULE2) +diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -C FORWARD $RULE3) +diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -C FORWARD $RULE4) +diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -C FORWARD $RULE5) EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination @@ -23,6 +35,9 @@ Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2 0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5 + 0 0 ipv6-icmp * * ::/0 ::/0 ipv6-icmptype 1 code 0 + 0 0 all * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 LOG all * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' -- cgit v1.2.3 From 9d54ddf5cbd6b1ce272972784e3cc056651a819f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 20 May 2021 11:58:09 +0200 Subject: tests: shell: Extend iptables-xml test a bit Call with --combine as well, even though output doesn't differ. Also there's no need to skip for xtables-nft-multi, it provides the same functionality. Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 index 50c0cae8..bcfaad36 100755 --- a/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 +++ b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 @@ -1,13 +1,5 @@ #!/bin/bash -case "$(basename $XT_MULTI)" in - xtables-legacy-multi) - ;; - *) - echo "skip $XT_MULTI" - exit 0 - ;; -esac - dump=$(dirname $0)/dumps/fedora27-iptables diff -u -Z <(cat ${dump}.xml) <($XT_MULTI iptables-xml <$dump) +diff -u -Z <(cat ${dump}.xml) <($XT_MULTI iptables-xml -c <$dump) -- cgit v1.2.3 From 0e4d9fcb7b79821fae9b9b704ae64db39f0de3a5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 8 Jun 2022 18:15:20 +0200 Subject: tests: shell: Extend zero counters test a bit further Test zeroing a single rule's counters as well. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/iptables/0007-zero-counters_0 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 index 36da1907..21793472 100755 --- a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 +++ b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 @@ -10,6 +10,7 @@ $XT_MULTI iptables-restore -c < Date: Thu, 20 May 2021 12:25:57 +0200 Subject: extensions: libebt_standard.t: Test logical-{in,out} as well These weren't used anywhere before. At least ensure they are only allowed where claimed. Signed-off-by: Phil Sutter --- extensions/libebt_standard.t | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t index c6c31727..97cb3baa 100644 --- a/extensions/libebt_standard.t +++ b/extensions/libebt_standard.t @@ -12,12 +12,17 @@ :INPUT -i foobar;=;OK -o foobar;=;FAIL +--logical-in br0;=;OK +--logical-out br1;=;FAIL :FORWARD -i foobar;=;OK -o foobar;=;OK +--logical-in br0 --logical-out br1;=;OK :OUTPUT -i foobar;=;FAIL -o foobar;=;OK +--logical-in br0;=;FAIL +--logical-out br1;=;OK :PREROUTING *nat -i foobar;=;OK -- cgit v1.2.3 From 276346f6659b700306070545f51c1a6060972f16 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Jun 2021 10:13:26 +0200 Subject: ebtables-restore: Deny --init-table Allowing this segfaults the program. The deny is in line with legacy ebtables, so no point in implementing support for that. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 3d15063e..b986fd9e 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -1077,6 +1077,9 @@ print_zero: flags |= LIST_MAC2; break; case 11: /* init-table */ + if (restore) + xtables_error(PARAMETER_PROBLEM, + "--init-table is not supported in daemon mode"); nft_cmd_table_flush(h, *table, false); return 1; case 13 : -- cgit v1.2.3 From 1bfb1d916e467e2bcbc44ce1a50a2be5c12b7ef8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 8 Jun 2022 13:28:10 +0200 Subject: extensions: string: Do not print default --to value Default value is UINT16_MAX, not 0. Fix the conditional printing. Fixes: c6fbf41cdd157 ("update string match to reflect new kernel implementation (Pablo Neira)") Signed-off-by: Phil Sutter --- extensions/libxt_string.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c index 739a8e7f..da05fad0 100644 --- a/extensions/libxt_string.c +++ b/extensions/libxt_string.c @@ -269,7 +269,7 @@ string_print(const void *ip, const struct xt_entry_match *match, int numeric) printf(" ALGO name %s", info->algo); if (info->from_offset != 0) printf(" FROM %u", info->from_offset); - if (info->to_offset != 0) + if (info->to_offset != UINT16_MAX) printf(" TO %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) printf(" ICASE"); @@ -293,7 +293,7 @@ static void string_save(const void *ip, const struct xt_entry_match *match) printf(" --algo %s", info->algo); if (info->from_offset != 0) printf(" --from %u", info->from_offset); - if (info->to_offset != 0) + if (info->to_offset != UINT16_MAX) printf(" --to %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) printf(" --icase"); -- cgit v1.2.3 From da5b32fb4656ab69fe1156eb7e36c7c961839e8a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 8 Jun 2022 13:45:13 +0200 Subject: extensions: string: Review parse_string() function * Compare against sizeof(info->pattern) which is more clear than having to know that this buffer is of size XT_STRING_MAX_PATTERN_SIZE * Invert the check and error early to reduce indenting * Pass info->patlen to memcpy() to avoid reading past end of 's' Signed-off-by: Phil Sutter --- extensions/libxt_string.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c index da05fad0..5d72a5cd 100644 --- a/extensions/libxt_string.c +++ b/extensions/libxt_string.c @@ -78,14 +78,13 @@ static void string_init(struct xt_entry_match *m) static void parse_string(const char *s, struct xt_string_info *info) -{ +{ /* xt_string does not need \0 at the end of the pattern */ - if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) { - memcpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE); - info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE); - return; - } - xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s); + if (strlen(s) > sizeof(info->pattern)) + xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s); + + info->patlen = strnlen(s, sizeof(info->pattern)); + memcpy(info->pattern, s, info->patlen); } static void -- cgit v1.2.3 From e81eea1be636b7ec0bc4091da483c08c0f6a016e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 8 Jun 2022 14:36:20 +0200 Subject: extensions: string: Fix and enable tests Some minor fixes were necessary: * --algo is printed after the pattern * Second long string test must fail, that string is 129 chars long * --from 0 and --to 65535 are not printed (default values) Signed-off-by: Phil Sutter --- extensions/libxt_string.t | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t index d68f099d..2f4b30cb 100644 --- a/extensions/libxt_string.t +++ b/extensions/libxt_string.t @@ -1,18 +1,11 @@ :INPUT,FORWARD,OUTPUT -# ERROR: cannot find: iptables -I INPUT -m string --algo bm --string "test" -# -m string --algo bm --string "test";=;OK -# ERROR: cannot find: iptables -I INPUT -m string --algo kmp --string "test") -# -m string --algo kmp --string "test";=;OK -# ERROR: cannot find: iptables -I INPUT -m string --algo kmp ! --string "test" -# -m string --algo kmp ! --string "test";=;OK -# cannot find: iptables -I INPUT -m string --algo bm --string "xxxxxxxxxxx" ....] -# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK -# ERROR: cannot load: iptables -A INPUT -m string --algo bm --string "xxxx" -# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK -# ERROR: cannot load: iptables -A INPUT -m string --algo bm --hexstring "|0a0a0a0a|" -# -m string --algo bm --hexstring "|0a0a0a0a|";=;OK -# ERROR: cannot find: iptables -I INPUT -m string --algo bm --from 0 --to 65535 --string "test" -# -m string --algo bm --from 0 --to 65535 --string "test";=;OK +-m string --algo bm --string "test";-m string --string "test" --algo bm;OK +-m string --string "test" --algo kmp;=;OK +-m string ! --string "test" --algo kmp;=;OK +-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;=;OK +-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;;FAIL +-m string --hex-string "|0a0a0a0a|" --algo bm;=;OK +-m string --algo bm --from 0 --to 65535 --string "test";-m string --string "test" --algo bm;OK -m string --algo wrong;;FAIL -m string --algo bm;;FAIL -m string;;FAIL -- cgit v1.2.3 From 15a31ba8e8e146a5dafce59160b2eeefb00bccca Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 17 Jun 2022 23:34:52 +0200 Subject: iptables.8: mention that iptables exits when setuid Signed-off-by: Florian Westphal --- iptables/iptables.8.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 627ff0e4..f81c632f 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -417,6 +417,11 @@ other errors cause an exit code of 1. .SH BUGS Bugs? What's this? ;-) Well, you might want to have a look at http://bugzilla.netfilter.org/ +\fBiptables\fP will exit immediately with an error code of 111 if it finds +that it was called as a setuid-to-root program. +iptables cannot be used safely in this manner because it trusts +the shared libraries (matches, targets) loaded at run time, the search +path can be set using environment variables. .SH COMPATIBILITY WITH IPCHAINS This \fBiptables\fP is very similar to ipchains by Rusty Russell. The main difference is -- cgit v1.2.3 From 2ce0014750c0afc06a87479462746ed113736025 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 14 Jun 2022 17:44:47 +0200 Subject: nft: Exit if nftnl_alloc_expr fails In some code-paths, 'reg' pointer remaining uninitialized is used later so at least minimal error checking is necessary. Given that a call to nftnl_alloc_expr() with sane argument should never fail, complain and exit if it happens. Fixes: 7e38890c6b4fb ("nft: prepare for dynamic register allocation") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 27e95c1a..74e19cca 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -40,15 +40,24 @@ extern struct nft_family_ops nft_family_ops_ipv6; extern struct nft_family_ops nft_family_ops_arp; extern struct nft_family_ops nft_family_ops_bridge; +static struct nftnl_expr *xt_nftnl_expr_alloc(const char *name) +{ + struct nftnl_expr *expr = nftnl_expr_alloc(name); + + if (expr) + return expr; + + xtables_error(RESOURCE_PROBLEM, + "Failed to allocate nftnl expression '%s'", name); +} + void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, uint8_t *dreg) { struct nftnl_expr *expr; uint8_t reg; - expr = nftnl_expr_alloc("meta"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("meta"); reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key); @@ -64,9 +73,7 @@ void add_payload(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_expr *expr; uint8_t reg; - expr = nftnl_expr_alloc("payload"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("payload"); reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); @@ -85,9 +92,7 @@ void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_expr *expr; uint8_t reg; - expr = nftnl_expr_alloc("bitwise"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("bitwise"); reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); @@ -107,9 +112,7 @@ void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, uint32_t xor[4] = { 0 }; uint8_t reg = *dreg; - expr = nftnl_expr_alloc("bitwise"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("bitwise"); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); @@ -126,9 +129,7 @@ void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, { struct nftnl_expr *expr; - expr = nftnl_expr_alloc("cmp"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("cmp"); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); -- cgit v1.2.3 From 6c12201b5ff08d9e1524477ff63bb8810198d638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Wed, 22 Jun 2022 21:56:47 +0200 Subject: xtables-monitor: add missing spaces in printed str MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when printing the ID and OPTs in iptables/xtables-monitor.c, a space is missing after the string, thereby concatenating the number with the next item in the printed PACKET line. Fixes: d26c538b9a549 ("xtables: add xtables-monitor") Signed-off-by: Anton Luka Šijanec Signed-off-by: Phil Sutter --- iptables/xtables-monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 905bb7fe..a1eba2f4 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -339,7 +339,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg inet_ntop(AF_INET, &iph->daddr, addrbuf, sizeof(addrbuf)); printf("DST=%s ", addrbuf); - printf("LEN=%d TOS=0x%x TTL=%d ID=%d", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id)); + printf("LEN=%d TOS=0x%x TTL=%d ID=%d ", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id)); if (iph->frag_off & htons(0x8000)) printf("CE "); if (iph->frag_off & htons(IP_DF)) @@ -362,7 +362,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg printf("OPT ("); for (i = 0; i < optsize; i++) printf("%02X", op[i]); - printf(")"); + printf(") "); } break; } -- cgit v1.2.3 From 0124019fb36859a77c32b6f96eeb4cc3e8ebb432 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 2 Jun 2022 10:53:31 +0200 Subject: libxtables: Move struct xtables_afinfo into xtables.h The library "owns" this structure and maintains 'afinfo' pointer to instances of it. With libxt_set, there's even an extension making use of the data. To avoid impact on library users, guard it by XTABLES_INTERNAL. To eliminate the xshared.h include by libxt_set, DEBUGP has to be redefined. Other extensions have similar defines, fix this later. Signed-off-by: Phil Sutter --- extensions/libxt_set.c | 6 ++++++ extensions/libxt_set.h | 1 - include/xtables.h | 22 ++++++++++++++++++++++ iptables/xshared.h | 22 ---------------------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c index 16921023..a2137ab1 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -22,6 +22,12 @@ #include #include "libxt_set.h" +#ifdef DEBUG +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + /* Revision 0 */ static void diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index ad895a75..597bf7eb 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -6,7 +6,6 @@ #include #include #include -#include "../iptables/xshared.h" static int get_version(unsigned *version) diff --git a/include/xtables.h b/include/xtables.h index f1937f3e..b8d8372d 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -665,6 +665,28 @@ void xtables_announce_chain(const char *name); extern void _init(void); +/** + * xtables_afinfo - protocol family dependent information + * @kmod: kernel module basename (e.g. "ip_tables") + * @proc_exists: file which exists in procfs when module already loaded + * @libprefix: prefix of .so library name (e.g. "libipt_") + * @family: nfproto family + * @ipproto: used by setsockopt (e.g. IPPROTO_IP) + * @so_rev_match: optname to check revision support of match + * @so_rev_target: optname to check revision support of target + */ +struct xtables_afinfo { + const char *kmod; + const char *proc_exists; + const char *libprefix; + uint8_t family; + uint8_t ipproto; + int so_rev_match; + int so_rev_target; +}; + +extern const struct xtables_afinfo *afinfo; + #endif /* XTABLES_INTERNAL */ #ifdef __cplusplus diff --git a/iptables/xshared.h b/iptables/xshared.h index 1d6b9bf4..1fdc760a 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -75,26 +75,6 @@ struct xtables_target; #define IPT_INV_ARPOP 0x0400 #define IPT_INV_ARPHRD 0x0800 -/** - * xtables_afinfo - protocol family dependent information - * @kmod: kernel module basename (e.g. "ip_tables") - * @proc_exists: file which exists in procfs when module already loaded - * @libprefix: prefix of .so library name (e.g. "libipt_") - * @family: nfproto family - * @ipproto: used by setsockopt (e.g. IPPROTO_IP) - * @so_rev_match: optname to check revision support of match - * @so_rev_target: optname to check revision support of target - */ -struct xtables_afinfo { - const char *kmod; - const char *proc_exists; - const char *libprefix; - uint8_t family; - uint8_t ipproto; - int so_rev_match; - int so_rev_target; -}; - /* trick for ebtables-compat, since watchers are targets */ struct ebt_match { struct ebt_match *next; @@ -187,8 +167,6 @@ int parse_counters(const char *string, struct xt_counters *ctr); bool tokenize_rule_counters(char **bufferp, char **pcnt, char **bcnt, int line); bool xs_has_arg(int argc, char *argv[]); -extern const struct xtables_afinfo *afinfo; - #define MAX_ARGC 255 struct argv_store { int argc; -- cgit v1.2.3 From 2c92bb9ba69cf4bec53b3f063f5b42284e2e28d9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 2 Jun 2022 11:16:38 +0200 Subject: libxtables: Define XT_OPTION_OFFSET_SCALE in xtables.h This is the last symbol in xshared.h used by libxtables, move it over. Again, treat this as "implementation detail" and hence put it behind XTABLES_INTERNAL-curtains. Signed-off-by: Phil Sutter --- include/xtables.h | 3 +++ iptables/xshared.h | 4 ---- libxtables/xtables.c | 1 - libxtables/xtoptions.c | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/xtables.h b/include/xtables.h index b8d8372d..9eba4f61 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -687,6 +687,9 @@ struct xtables_afinfo { extern const struct xtables_afinfo *afinfo; +/* base offset of merged extensions' consecutive options */ +#define XT_OPTION_OFFSET_SCALE 256 + #endif /* XTABLES_INTERNAL */ #ifdef __cplusplus diff --git a/iptables/xshared.h b/iptables/xshared.h index 1fdc760a..1a019a7c 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -132,10 +132,6 @@ struct subcommand { mainfunc_t main; }; -enum { - XT_OPTION_OFFSET_SCALE = 256, -}; - extern int subcmd_main(int, char **, const struct subcommand *); extern void xs_init_target(struct xtables_target *); extern void xs_init_match(struct xtables_match *); diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 0638f927..dc645162 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -64,7 +64,6 @@ #endif #include #include "iptables/internal.h" -#include "xshared.h" #define NPROTO 255 diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c index 9d3ac5c8..8174a560 100644 --- a/libxtables/xtoptions.c +++ b/libxtables/xtoptions.c @@ -21,7 +21,6 @@ #include #include #include "xtables.h" -#include "xshared.h" #ifndef IPTOS_NORMALSVC # define IPTOS_NORMALSVC 0 #endif -- cgit v1.2.3 From 9ea7e6aa638d0dfa14613f6f97e6dc06c857e609 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Thu, 16 Jun 2022 15:48:18 -0700 Subject: netfilter: add nf_log.h Since libxt_NFLOG is now using the UAPI version of nf_log.h, it should be bundled alongside the other netfilter kernel headers. This copy of nf_log.h was taken from Linux 5.18. Signed-off-by: Markus Mayer Signed-off-by: Florian Westphal --- include/linux/netfilter/nf_log.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 include/linux/netfilter/nf_log.h diff --git a/include/linux/netfilter/nf_log.h b/include/linux/netfilter/nf_log.h new file mode 100644 index 00000000..2ae00932 --- /dev/null +++ b/include/linux/netfilter/nf_log.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _NETFILTER_NF_LOG_H +#define _NETFILTER_NF_LOG_H + +#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define NF_LOG_TCPOPT 0x02 /* Log TCP options */ +#define NF_LOG_IPOPT 0x04 /* Log IP options */ +#define NF_LOG_UID 0x08 /* Log UID owning local socket */ +#define NF_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define NF_LOG_MASK 0x2f + +#define NF_LOG_PREFIXLEN 128 + +#endif /* _NETFILTER_NF_LOG_H */ -- cgit v1.2.3 From 552c4a2f9e5706fef5f7abb27d1492a78bbb2a37 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 30 Jun 2022 18:04:39 +0200 Subject: libxtables: Fix unsupported extension warning corner case Some extensions are not supported in revision 0 by user space anymore, for those the warning in xtables_compatible_revision() does not print as no revision 0 is tried. To fix this, one has to track if none of the user space supported revisions were accepted by the kernel. Therefore add respective logic to xtables_find_{target,match}(). Note that this does not lead to duplicated warnings for unsupported extensions that have a revision 0 because xtables_compatible_revision() returns true for them to allow for extension's help output. For the record, these ip6tables extensions are affected: set/SET, socket, tos/TOS, TPROXY and SNAT. In addition to that, TEE is affected for both families. Fixes: 17534cb18ed0a ("Improve error messages for unsupported extensions") Signed-off-by: Phil Sutter --- libxtables/xtables.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index dc645162..479dbae0 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -776,6 +776,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, struct xtables_match *ptr; const char *icmp6 = "icmp6"; bool found = false; + bool seen = false; if (strlen(name) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -794,6 +795,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; + seen = true; if (!found && xtables_fully_register_pending_match(ptr, prev)) { found = true; @@ -807,6 +809,11 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, dptr = &((*dptr)->next); } + if (seen && !found) + fprintf(stderr, + "Warning: Extension %s is not supported, missing kernel module?\n", + name); + for (ptr = xtables_matches; ptr; ptr = ptr->next) { if (extension_cmp(name, ptr->name, ptr->family)) { struct xtables_match *clone; @@ -899,6 +906,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) struct xtables_target **dptr; struct xtables_target *ptr; bool found = false; + bool seen = false; /* Standard target? */ if (strcmp(name, "") == 0 @@ -917,6 +925,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { ptr = *dptr; *dptr = (*dptr)->next; + seen = true; if (!found && xtables_fully_register_pending_target(ptr, prev)) { found = true; @@ -930,6 +939,11 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) dptr = &((*dptr)->next); } + if (seen && !found) + fprintf(stderr, + "Warning: Extension %s is not supported, missing kernel module?\n", + name); + for (ptr = xtables_targets; ptr; ptr = ptr->next) { if (extension_cmp(name, ptr->name, ptr->family)) { struct xtables_target *clone; -- cgit v1.2.3 From 6b04d9c34e25e2aa3e6b28c74e683021fc7c0c08 Mon Sep 17 00:00:00 2001 From: Yuxuan Luo Date: Mon, 11 Jul 2022 12:12:38 -0400 Subject: xt_sctp: support a couple of new chunk types There are new chunks added in Linux SCTP not being traced by iptables. This patch introduces the following chunks for tracing: I_DATA, I_FORWARD_TSN (RFC8260), RE_CONFIG(RFC6525) and PAD(RFC4820) Signed-off-by: Yuxuan Luo Signed-off-by: Phil Sutter --- extensions/libxt_sctp.c | 4 ++++ extensions/libxt_sctp.man | 4 +++- extensions/libxt_sctp.t | 4 ++++ extensions/libxt_sctp.txlate | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index a4c5415f..3fb6cf1a 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -112,9 +112,13 @@ static const struct sctp_chunk_names sctp_chunk_names[] { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" }, { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" }, { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" }, + { .name = "I_DATA", .chunk_type = 64, .valid_flags = "----IUBE", .nftname = "i-data"}, + { .name = "RE_CONFIG", .chunk_type = 130, .valid_flags = "--------", .nftname = "re-config"}, + { .name = "PAD", .chunk_type = 132, .valid_flags = "--------", .nftname = "pad"}, { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" }, { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" }, { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" }, + { .name = "I_FORWARD_TSN", .chunk_type = 194, .valid_flags = "--------", .nftname = "i-forward-tsn" }, }; static void diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man index 3e5ffa09..06da04f8 100644 --- a/extensions/libxt_sctp.man +++ b/extensions/libxt_sctp.man @@ -19,12 +19,14 @@ Match if any of the given chunk types is present with given flags. only Match if only the given chunk types are present with given flags and none are missing. -Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN +Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN chunk type available flags .br DATA I U B E i u b e .br +I_DATA I U B E i u b e +.br ABORT T t .br SHUTDOWN_COMPLETE T t diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t index 4016e4fb..4d3b113d 100644 --- a/extensions/libxt_sctp.t +++ b/extensions/libxt_sctp.t @@ -27,3 +27,7 @@ -p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK -p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK -p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK +-p sctp -m sctp --chunk-types all I_DATA;=;OK +-p sctp -m sctp --chunk-types all RE_CONFIG;=;OK +-p sctp -m sctp --chunk-types all PAD;=;OK +-p sctp -m sctp --chunk-types all I_FORWARD_TSN;=;OK diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate index bb817525..6443abf9 100644 --- a/extensions/libxt_sctp.txlate +++ b/extensions/libxt_sctp.txlate @@ -41,4 +41,4 @@ iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT: nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT -nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing counter accept +nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk i-data missing sctp chunk re-config missing sctp chunk pad missing sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing sctp chunk i-forward-tsn missing counter accept -- cgit v1.2.3 From e88085ac41b4c962e1d85dcc8dc6fa0d1f80dc12 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 23 Jul 2022 20:25:49 +0200 Subject: extensions: libxt_conntrack: remove always-false conditionals libxt_conntrack.c:1292: warning: the comparison will always evaluate as false for the address of origsrc_addr will never be NULL [-Waddress] Signed-off-by: Florian Westphal --- extensions/libxt_conntrack.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 234085c5..08dba42d 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1289,9 +1289,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) { - if (&sinfo->origsrc_addr == 0L) - return 0; - xt_xlate_add(xl, "%sct original saddr %s", space, sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ? "!= " : ""); @@ -1301,9 +1298,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) { - if (&sinfo->origdst_addr == 0L) - return 0; - xt_xlate_add(xl, "%sct original daddr %s", space, sinfo->invert_flags & XT_CONNTRACK_ORIGDST ? "!= " : ""); @@ -1313,9 +1307,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) { - if (&sinfo->replsrc_addr == 0L) - return 0; - xt_xlate_add(xl, "%sct reply saddr %s", space, sinfo->invert_flags & XT_CONNTRACK_REPLSRC ? "!= " : ""); @@ -1325,9 +1316,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_REPLDST) { - if (&sinfo->repldst_addr == 0L) - return 0; - xt_xlate_add(xl, "%sct reply daddr %s", space, sinfo->invert_flags & XT_CONNTRACK_REPLDST ? "!= " : ""); -- cgit v1.2.3 From 6e41c2d8747b25ed08dff41bbb9f77fb35bc1851 Mon Sep 17 00:00:00 2001 From: Erik Skultety Date: Wed, 20 Jul 2022 15:06:50 +0200 Subject: iptables: xshared: Ouptut '--' in the opt field in ipv6's fake mode The fact that the 'opt' table field reports spaces instead of '--' for IPv6 as it would have been the case with IPv4 has a bit of an unfortunate side effect that it completely confuses the 'jc' JSON formatter tool (which has an iptables formatter module). Consider: # ip6tables -L test Chain test (0 references) target prot opt source destination ACCEPT all a:b:c:: anywhere MAC01:02:03:04:05:06 Then: # ip6tables -L test | jc --iptables [{"chain":"test", "rules":[ {"target":"ACCEPT", "prot":"all", "opt":"a:b:c::", "source":"anywhere", "destination":"MAC01:02:03:04:05:06" }] }] which as you can see is wrong simply because whitespaces are considered as a column delimiter. [ Florian: added 'Link' for more background info. The '--' difference exists for > 20 years, but changing it appears to be least intrusive option. ] Link: https://lore.kernel.org/netfilter-devel/bb391c763171f0c5511f73e383e1b2e6a53e2014.1658322396.git.eskultet@redhat.com/t/#u Signed-off-by: Erik Skultety Signed-off-by: Florian Westphal --- iptables/xshared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index bd4e1022..b1088c82 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -731,7 +731,7 @@ void print_fragment(unsigned int flags, unsigned int invflags, fputs("opt ", stdout); if (fake) { - fputs(" ", stdout); + fputs("--", stdout); } else { fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout); fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); -- cgit v1.2.3 From 68e09d49ef26c024e3c541d0427e389da0d5dc67 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 28 Jul 2022 13:02:50 +0200 Subject: tests: shell: Fix testcases for changed ip6tables opts output Adjust captured output, ip6tables prints '--' instead of spaces since the commit in Fixes: tag. Fixes: 6e41c2d8747b2 ("iptables: xshared: Ouptut '--' in the opt field in ipv6's fake mode") Signed-off-by: Phil Sutter --- .../shell/testcases/ip6tables/0002-verbose-output_0 | 20 ++++++++++---------- .../testcases/ipt-restore/0014-verbose-restore_0 | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index 7624cbab..4e754156 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -6,15 +6,15 @@ set -e # ensure verbose output is identical between legacy and nft tools RULE1='-i eth2 -o eth3 -s feed:babe::1 -d feed:babe::2 -j ACCEPT' -VOUT1='ACCEPT all opt in eth2 out eth3 feed:babe::1 -> feed:babe::2' +VOUT1='ACCEPT all opt -- in eth2 out eth3 feed:babe::1 -> feed:babe::2' RULE2='-i eth2 -o eth3 -s feed:babe::4 -d feed:babe::5 -j ACCEPT' -VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5' +VOUT2='ACCEPT all opt -- in eth2 out eth3 feed:babe::4 -> feed:babe::5' RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route' -VOUT3=' ipv6-icmp opt in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' +VOUT3=' ipv6-icmp opt -- in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' RULE4='-m dst --dst-len 42 -m rt --rt-type 23' -VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23' +VOUT4=' all opt -- in * out * ::/0 -> ::/0 dst length:42 rt type:23' RULE5='-m frag --fragid 1337 -j LOG' -VOUT5='LOG all opt in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' +VOUT5='LOG all opt -- in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -A FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -I FORWARD 2 $RULE2) @@ -33,11 +33,11 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2 - 0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5 - 0 0 ipv6-icmp * * ::/0 ::/0 ipv6-icmptype 1 code 0 - 0 0 all * * ::/0 ::/0 dst length:42 rt type:23 - 0 0 LOG all * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 + 0 0 ACCEPT all -- eth2 eth3 feed:babe::1 feed:babe::2 + 0 0 ACCEPT all -- eth2 eth3 feed:babe::4 feed:babe::5 + 0 0 ipv6-icmp-- * * ::/0 ::/0 ipv6-icmptype 1 code 0 + 0 0 all -- * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 LOG all -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 index 5daf7a78..087156b1 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 @@ -60,7 +60,7 @@ Flushing chain \`OUTPUT' Flushing chain \`secfoo' Deleting chain \`secfoo'" -EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' -e 's/opt --/opt /' <<< "$EXPECT") +EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' <<< "$EXPECT") diff -u -Z <(echo "$EXPECT") <($XT_MULTI iptables-restore -v <<< "$DUMP") diff -u -Z <(echo "$EXPECT6") <($XT_MULTI ip6tables-restore -v <<< "$DUMP") -- cgit v1.2.3 From ba98dc47073b46c3a514039baaddcebecb4e738d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 27 Jul 2022 14:14:23 +0200 Subject: xshared: Fix for missing space after 'prot' column Format string ensured a minimum field width of five characters, but allowed for longer strings to eat the column delimiting white space. Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 | 2 +- iptables/xshared.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index 4e754156..dad01a98 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -35,7 +35,7 @@ Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- eth2 eth3 feed:babe::1 feed:babe::2 0 0 ACCEPT all -- eth2 eth3 feed:babe::4 feed:babe::5 - 0 0 ipv6-icmp-- * * ::/0 ::/0 ipv6-icmptype 1 code 0 + 0 0 ipv6-icmp -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 0 0 all -- * * ::/0 ::/0 dst length:42 rt type:23 0 0 LOG all -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 diff --git a/iptables/xshared.c b/iptables/xshared.c index b1088c82..ccec4ff1 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1093,9 +1093,9 @@ void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); if (pname) - printf(FMT("%-5s", "%s "), pname); + printf(FMT("%-4s ", "%s "), pname); else - printf(FMT("%-5hu", "%hu "), proto); + printf(FMT("%-4hu ", "%hu "), proto); } void save_rule_details(const char *iniface, unsigned const char *iniface_mask, -- cgit v1.2.3 From da8ecc62dd765b15df84c3aa6b83dcb7a81d4ffa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 28 Jul 2022 12:31:36 +0200 Subject: xshared: Print protocol numbers if --numeric was given This is much trickier than expected: On one hand, proto_to_name() is used to lookup protocol extensions so must resolve despite FMT_NUMERIC being set. On the other, --verbose implies --numeric but changing the output there is probably a bad idea. Luckily the latter situation is identified by FMT_NOTABLE bit. Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 | 10 +++++----- .../shell/testcases/ipt-restore/0011-noflush-empty-line_0 | 2 +- iptables/tests/shell/testcases/iptables/0002-verbose-output_0 | 4 ++-- iptables/xshared.c | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index dad01a98..2a1518d6 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -33,11 +33,11 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT all -- eth2 eth3 feed:babe::1 feed:babe::2 - 0 0 ACCEPT all -- eth2 eth3 feed:babe::4 feed:babe::5 - 0 0 ipv6-icmp -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 - 0 0 all -- * * ::/0 ::/0 dst length:42 rt type:23 - 0 0 LOG all -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 + 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::1 feed:babe::2 + 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::4 feed:babe::5 + 0 0 58 -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 + 0 0 0 -- * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 LOG 0 -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 index bea1a690..1a3af46f 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 @@ -12,5 +12,5 @@ EOF EXPECT='Chain FORWARD (policy ACCEPT) target prot opt source destination -ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ' +ACCEPT 0 -- 0.0.0.0/0 0.0.0.0/0 ' diff -u <(echo "$EXPECT") <($XT_MULTI iptables -n -L FORWARD) diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index 5d2af4c8..15c72af3 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -21,8 +21,8 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT all -- eth2 eth3 10.0.0.1 10.0.0.2 - 0 0 ACCEPT all -- eth2 eth3 10.0.0.4 10.0.0.5 + 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.1 10.0.0.2 + 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.4 10.0.0.5 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/xshared.c b/iptables/xshared.c index ccec4ff1..69515789 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1092,10 +1092,10 @@ void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); - if (pname) - printf(FMT("%-4s ", "%s "), pname); - else + if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname) printf(FMT("%-4hu ", "%hu "), proto); + else + printf(FMT("%-4s ", "%s "), pname); } void save_rule_details(const char *iniface, unsigned const char *iniface_mask, -- cgit v1.2.3 From 2ba74d421cd622757df7a93720afc3b5b4b3b4e0 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 2 Aug 2022 14:52:30 +0200 Subject: nft: fix ebtables among match when mac+ip addresses are used When matching mac and ip addresses, the ip address needs to be placed into then 2nd 32bit register, the switch to dynamic register allocation instead re-uses reg1, this partially clobbers the mac address, so set lookup comes up empty even though it should find a match. Fixes: 7e38890c6b4fb ("nft: prepare for dynamic register allocation") Reported-by: Yi Chen Signed-off-by: Florian Westphal --- iptables/nft.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index ec79f2bc..ee003511 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1208,8 +1208,8 @@ static int __add_nft_among(struct nft_handle *h, const char *table, nftnl_rule_add_expr(r, e); if (ip) { - e = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], - sizeof(struct in_addr), ®); + e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], + sizeof(struct in_addr), NFT_REG32_02); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); -- cgit v1.2.3 From ead69273d16dae2da54e510f7ffb58fd880567d1 Mon Sep 17 00:00:00 2001 From: Yi Chen Date: Wed, 3 Aug 2022 09:14:55 +0200 Subject: tests: add ebtables among testcase Validate that matching works as expected. Signed-off-by: Florian Westphal --- .../shell/testcases/ebtables/0008-ebtables-among_0 | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100755 iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 diff --git a/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 new file mode 100755 index 00000000..b5df9725 --- /dev/null +++ b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 @@ -0,0 +1,98 @@ +#!/bin/sh + +case "$XT_MULTI" in +*xtables-nft-multi) + ;; +*) + echo "skip $XT_MULTI" + exit 0 + ;; +esac + +sfx=$(mktemp -u "XXXXXXXX") +nsa="nsa-$sfx" +nsb="nsb-$sfx" +nsc="nsc-$sfx" + +cleanup() +{ + ip netns del "$nsa" + ip netns del "$nsb" + ip netns del "$nsc" +} + +trap cleanup EXIT + +assert_fail() +{ + if [ $1 -eq 0 ]; then + echo "FAILED: $2" + exit 1 + fi +} + +assert_pass() +{ + if [ $1 -ne 0 ]; then + echo "FAILED: $2" + exit 2 + fi +} + +ip netns add "$nsa" +ip netns add "$nsb" +ip netns add "$nsc" + +ip link add name c_b netns "$nsc" type veth peer name b_c netns "$nsb" +ip link add name s_b netns "$nsa" type veth peer name b_s netns "$nsb" +ip netns exec "$nsb" ip link add name br0 type bridge + +ip -net "$nsb" link set b_c up +ip netns exec "$nsb" ip link set b_s up +ip netns exec "$nsb" ip addr add 10.167.11.254/24 dev br0 +ip netns exec "$nsb" ip link set br0 up +ip netns exec "$nsb" ip link set b_c master br0 +ip netns exec "$nsb" ip link set b_s master br0 +ip netns exec "$nsc" ip addr add 10.167.11.2/24 dev c_b +ip netns exec "$nsc" ip link set c_b up +ip -net "$nsa" addr add 10.167.11.1/24 dev s_b +ip -net "$nsa" link set s_b up + +ip netns exec "$nsc" ping -q 10.167.11.1 -c1 >/dev/null || exit 1 + +bf_bridge_mac1=`ip netns exec "$nsb" cat /sys/class/net/b_s/address` +bf_bridge_mac0=`ip netns exec "$nsb" cat /sys/class/net/b_c/address` +bf_client_mac1=`ip netns exec "$nsc" cat /sys/class/net/c_b/address` +bf_server_mac1=`ip netns exec "$nsa" cat /sys/class/net/s_b/address` + +bf_server_ip1="10.167.11.1" +bf_bridge_ip0="10.167.11.254" +bf_client_ip1="10.167.11.2" +pktsize=64 + +# --among-src [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-dst $bf_server_ip1 --among-src $bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null +assert_fail $? "--among-src [match]" + +# ip netns exec "$nsb" $XT_MULTI ebtables -L --Ln --Lc + +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-dst $bf_server_ip1 --among-src ! $bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null +assert_pass $? "--among-src [not match]" + +# --among-dst [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-src $bf_client_ip1 --among-dst $bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null +assert_fail $? "--among-dst [match]" + +# --among-dst ! [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-src $bf_client_ip1 --among-dst ! $bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null +assert_pass $? "--among-dst [not match]" + +exit 0 -- cgit v1.2.3 From c70a33d219ccb43e6f59aa1b9bbab5dcb13f3443 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 25 Aug 2022 11:53:04 +0200 Subject: xtables-restore: Extend failure error message If a line causes zero 'ret' value and errno is set, call nft_strerror() for a more detailed error message. While not perfect, it helps with debugging ominous "line NN failed" messages pointing at COMMIT: | # iptables-nft-restore < --- iptables/xtables-restore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 1363f96a..052a80c2 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -249,8 +249,11 @@ static void xtables_restore_parse_line(struct nft_handle *h, (strcmp(p->tablename, state->curtable->name) != 0)) return; if (!ret) { - fprintf(stderr, "%s: line %u failed\n", + fprintf(stderr, "%s: line %u failed", xt_params->program_name, line); + if (errno) + fprintf(stderr, ": %s.", nft_strerror(errno)); + fprintf(stderr, "\n"); exit(1); } } -- cgit v1.2.3 From 0257293c68913dd5993c1cac44f2ee80af6d9792 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 26 Aug 2022 16:53:52 +0200 Subject: nft: Expand extended error reporting to nft_cmd, too Introduce the same embedded 'error' struct in nft_cmd and initialize it with the current value from nft_handle. Then in preparation phase, update nft_handle's error.lineno with the value from the current nft_cmd. This serves two purposes: * Allocated batch objects (obj_update) get the right lineno value instead of the COMMIT one. * Any error during preparation may be reported with line number. Do this and change the relevant fprintf() call to use nft_handle's lineno instead of the global 'line' variable. With this change, cryptic iptables-nft-restore error messages should finally be gone: | # iptables-nft-restore < --- iptables/nft-cmd.c | 1 + iptables/nft-cmd.h | 3 +++ iptables/nft.c | 2 ++ iptables/xtables-restore.c | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index fcd01bd0..f16ea0e6 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -24,6 +24,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, struct nft_cmd *cmd; cmd = xtables_calloc(1, sizeof(struct nft_cmd)); + cmd->error.lineno = h->error.lineno; cmd->command = command; cmd->table = xtables_strdup(table); if (chain) diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h index b5a99ef7..c0f84636 100644 --- a/iptables/nft-cmd.h +++ b/iptables/nft-cmd.h @@ -24,6 +24,9 @@ struct nft_cmd { struct xt_counters counters; const char *rename; int counters_save; + struct { + unsigned int lineno; + } error; }; struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, diff --git a/iptables/nft.c b/iptables/nft.c index ee003511..fd552506 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3360,6 +3360,8 @@ static int nft_prepare(struct nft_handle *h) nft_cache_build(h); list_for_each_entry_safe(cmd, next, &h->cmd_list, head) { + h->error.lineno = cmd->error.lineno; + switch (cmd->command) { case NFT_COMPAT_TABLE_FLUSH: ret = nft_table_flush(h, cmd->table); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 052a80c2..c9d4ffbf 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -250,7 +250,7 @@ static void xtables_restore_parse_line(struct nft_handle *h, return; if (!ret) { fprintf(stderr, "%s: line %u failed", - xt_params->program_name, line); + xt_params->program_name, h->error.lineno); if (errno) fprintf(stderr, ": %s.", nft_strerror(errno)); fprintf(stderr, "\n"); -- cgit v1.2.3 From 988147adb4ab8a2dc9f0bf01e8bc24e236f98417 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 8 Sep 2022 17:12:40 +0200 Subject: nft: support dissection of meta pkktype mode Makes iptables-nft-save dump 'nft meta pkttype' rules. Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- iptables/nft-shared.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 74e19cca..79c93fe8 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -323,6 +324,27 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) return 0; } +static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_pkttype_info *pkttype; + struct xtables_match *match; + uint8_t value; + + match = nft_create_match(ctx, ctx->cs, "pkttype"); + if (!match) + return -1; + + pkttype = (void*)match->m->data; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + pkttype->invert = 1; + + value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + pkttype->pkttype = value; + + return 0; +} + int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags) @@ -369,6 +391,9 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, case NFT_META_MARK: parse_meta_mark(ctx, e); break; + case NFT_META_PKTTYPE: + parse_meta_pkttype(ctx, e); + break; default: return -1; } -- cgit v1.2.3 From 793caef9076cceb24336b6cbb8f55107de49f269 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 8 Sep 2022 17:12:41 +0200 Subject: nft: prefer native 'meta pkttype' instead of xt match Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- iptables/nft.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index fd552506..a7f712b1 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -1445,6 +1446,25 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, return 0; } +static int add_nft_pkttype(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_match *m) +{ + struct xt_pkttype_info *pkti = (void *)m->data; + uint8_t reg; + int op; + + add_meta(h, r, NFT_META_PKTTYPE, ®); + + if (pkti->invert) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_cmp_u8(r, pkti->pkttype, op, reg); + + return 0; +} + int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1461,6 +1481,8 @@ int add_match(struct nft_handle *h, return add_nft_tcp(h, r, m); else if (!strcmp(m->u.user.name, "mark")) return add_nft_mark(h, r, m); + else if (!strcmp(m->u.user.name, "pkttype")) + return add_nft_pkttype(h, r, m); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From 0da2d1a35bd70d37f72d594927c0649d1dea4f7c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 8 Sep 2022 17:12:42 +0200 Subject: extensions: libxt_pkttype: support otherhost Makes no sense for iptables/ip6tables but it does make sense for ebtables. Classic ebtables uses libebt_pkttype which isn't compatible, but iptables-nft can use the libxt_pkttype version when printing native 'meta pkttype'. Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- extensions/libxt_pkttype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_pkttype.c b/extensions/libxt_pkttype.c index bf6f5b96..a76310b0 100644 --- a/extensions/libxt_pkttype.c +++ b/extensions/libxt_pkttype.c @@ -30,8 +30,8 @@ static const struct pkttypes supported_types[] = { {"unicast", PACKET_HOST, 1, "to us"}, {"broadcast", PACKET_BROADCAST, 1, "to all"}, {"multicast", PACKET_MULTICAST, 1, "to group"}, -/* {"otherhost", PACKET_OTHERHOST, 1, "to someone else"}, +/* {"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"}, */ /* aliases */ -- cgit v1.2.3 From b4fd0f682b53609c747e6dd69cc5024545d4b90c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 12 Sep 2022 10:58:44 +0200 Subject: nft: support ttl/hoplimit dissection xlate raw "nft ... ttl eq 1" and so on to the ttl/hl matches. Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- iptables/nft-ipv4.c | 3 +++ iptables/nft-ipv6.c | 3 +++ iptables/nft-shared.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ iptables/nft-shared.h | 2 ++ 4 files changed, 76 insertions(+) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 59c4a41f..1865d151 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -206,6 +206,9 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, if (inv) cs->fw.ip.invflags |= IPT_INV_FRAG; break; + case offsetof(struct iphdr, ttl): + nft_parse_hl(ctx, e, cs); + break; default: DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 9a29d18b..0ab1f971 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -169,6 +169,9 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, cs->fw6.ipv6.proto = proto; if (inv) cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; + case offsetof(struct ip6_hdr, ip6_hlim): + nft_parse_hl(ctx, e, cs); + break; default: DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 79c93fe8..71e2f18d 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -1449,3 +1451,69 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) prefix, prefix, is_ipt_save ? "-save" : ""); fclose(fp); } + +int nft_parse_hl(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct xtables_match *match; + struct ip6t_hl_info *info; + uint8_t hl, mode; + int op; + + hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + switch (op) { + case NFT_CMP_NEQ: + mode = IP6T_HL_NE; + break; + case NFT_CMP_EQ: + mode = IP6T_HL_EQ; + break; + case NFT_CMP_LT: + mode = IP6T_HL_LT; + break; + case NFT_CMP_GT: + mode = IP6T_HL_GT; + break; + case NFT_CMP_LTE: + mode = IP6T_HL_LT; + if (hl == 255) + return -1; + hl++; + break; + case NFT_CMP_GTE: + mode = IP6T_HL_GT; + if (hl == 0) + return -1; + hl--; + break; + default: + return -1; + } + + /* ipt_ttl_info and ip6t_hl_info have same layout, + * IPT_TTL_x and IP6T_HL_x are aliases as well, so + * just use HL for both ipv4 and ipv6. + */ + switch (ctx->h->family) { + case NFPROTO_IPV4: + match = nft_create_match(ctx, ctx->cs, "ttl"); + break; + case NFPROTO_IPV6: + match = nft_create_match(ctx, ctx->cs, "hl"); + break; + default: + return -1; + } + + if (!match) + return -1; + + info = (void*)match->m->data; + info->hop_limit = hl; + info->mode = mode; + + return 0; +} diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index b0404904..0718dc23 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -212,6 +212,8 @@ void xtables_restore_parse(struct nft_handle *h, void nft_check_xt_legacy(int family, bool is_ipt_save); +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs); + #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -- cgit v1.2.3 From 8acaccf69c22fb195a0b88e28489792304728245 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 12 Sep 2022 10:58:46 +0200 Subject: nft: prefer payload to ttl/hl module Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- iptables/nft.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index a7f712b1..f31c1603 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -43,6 +43,8 @@ #include #include +#include + #include #include #include @@ -1465,6 +1467,41 @@ static int add_nft_pkttype(struct nft_handle *h, struct nftnl_rule *r, return 0; } +static int add_nft_hl(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_match *m, uint8_t offset) +{ + struct ip6t_hl_info *info = (void *)m->data; + struct nftnl_expr *expr; + uint8_t reg; + uint8_t op; + + switch (info->mode) { + case IP6T_HL_NE: + op = NFT_CMP_NEQ; + break; + case IP6T_HL_EQ: + op = NFT_CMP_EQ; + break; + case IP6T_HL_LT: + op = NFT_CMP_LT; + break; + case IP6T_HL_GT: + op = NFT_CMP_GT; + break; + default: + return -EINVAL; + } + + expr = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, offset, 1, ®); + if (!expr) + return -ENOMEM; + + nftnl_rule_add_expr(r, expr); + add_cmp_u8(r, info->hop_limit, op, reg); + + return 0; +} + int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1483,6 +1520,12 @@ int add_match(struct nft_handle *h, return add_nft_mark(h, r, m); else if (!strcmp(m->u.user.name, "pkttype")) return add_nft_pkttype(h, r, m); + else if (!strcmp(m->u.user.name, "hl")) + return add_nft_hl(h, r, m, + offsetof(struct ip6_hdr, ip6_hlim)); + else if (!strcmp(m->u.user.name, "ttl")) + return add_nft_hl(h, r, m, + offsetof(struct iphdr, ttl)); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From 32efb4ffc33ae874b3f26f3380e2184ad6ceb26f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 22 Sep 2022 13:33:50 +0200 Subject: nft: un-break among match with concatenation The kernel commit 88cccd908d51 ("netfilter: nf_tables: NFTA_SET_ELEM_KEY_END requires concat and interval flags") breaks ebtables-nft 'among' emulation, it sets NFTA_SET_ELEM_KEY_END but doesn't set the CONCAT flag. Update uapi header and also set CONCAT. Signed-off-by: Florian Westphal --- include/linux/netfilter/nf_tables.h | 483 +++++++++++++++++++++++++++++++++++- iptables/nft.c | 2 +- 2 files changed, 476 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 66dceee0..e94d1fa5 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -8,6 +8,7 @@ #define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN #define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN #define NFT_USERDATA_MAXLEN 256 +#define NFT_OSF_MAXGENRELEN 16 /** * enum nft_registers - nf_tables registers @@ -47,6 +48,7 @@ enum nft_registers { #define NFT_REG_SIZE 16 #define NFT_REG32_SIZE 4 +#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1) /** * enum nft_verdicts - nf_tables internal verdicts @@ -131,7 +133,7 @@ enum nf_tables_msg_types { * @NFTA_LIST_ELEM: list element (NLA_NESTED) */ enum nft_list_attributes { - NFTA_LIST_UNPEC, + NFTA_LIST_UNSPEC, NFTA_LIST_ELEM, __NFTA_LIST_MAX }; @@ -143,12 +145,14 @@ enum nft_list_attributes { * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32) * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32) * @NFTA_HOOK_DEV: netdevice name (NLA_STRING) + * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED) */ enum nft_hook_attributes { NFTA_HOOK_UNSPEC, NFTA_HOOK_HOOKNUM, NFTA_HOOK_PRIORITY, NFTA_HOOK_DEV, + NFTA_HOOK_DEVS, __NFTA_HOOK_MAX }; #define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1) @@ -160,7 +164,10 @@ enum nft_hook_attributes { */ enum nft_table_flags { NFT_TABLE_F_DORMANT = 0x1, + NFT_TABLE_F_OWNER = 0x2, }; +#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \ + NFT_TABLE_F_OWNER) /** * enum nft_table_attributes - nf_tables table netlink attributes @@ -168,6 +175,8 @@ enum nft_table_flags { * @NFTA_TABLE_NAME: name of the table (NLA_STRING) * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) + * @NFTA_TABLE_USERDATA: user data (NLA_BINARY) + * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32) */ enum nft_table_attributes { NFTA_TABLE_UNSPEC, @@ -176,10 +185,21 @@ enum nft_table_attributes { NFTA_TABLE_USE, NFTA_TABLE_HANDLE, NFTA_TABLE_PAD, + NFTA_TABLE_USERDATA, + NFTA_TABLE_OWNER, __NFTA_TABLE_MAX }; #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) +enum nft_chain_flags { + NFT_CHAIN_BASE = (1 << 0), + NFT_CHAIN_HW_OFFLOAD = (1 << 1), + NFT_CHAIN_BINDING = (1 << 2), +}; +#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \ + NFT_CHAIN_HW_OFFLOAD | \ + NFT_CHAIN_BINDING) + /** * enum nft_chain_attributes - nf_tables chain netlink attributes * @@ -191,6 +211,9 @@ enum nft_table_attributes { * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32) * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING) * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes) + * @NFTA_CHAIN_FLAGS: chain flags + * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32) + * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY) */ enum nft_chain_attributes { NFTA_CHAIN_UNSPEC, @@ -203,6 +226,9 @@ enum nft_chain_attributes { NFTA_CHAIN_TYPE, NFTA_CHAIN_COUNTERS, NFTA_CHAIN_PAD, + NFTA_CHAIN_FLAGS, + NFTA_CHAIN_ID, + NFTA_CHAIN_USERDATA, __NFTA_CHAIN_MAX }; #define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1) @@ -218,6 +244,7 @@ enum nft_chain_attributes { * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64) * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN) * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32) + * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32) */ enum nft_rule_attributes { NFTA_RULE_UNSPEC, @@ -230,6 +257,8 @@ enum nft_rule_attributes { NFTA_RULE_USERDATA, NFTA_RULE_PAD, NFTA_RULE_ID, + NFTA_RULE_POSITION_ID, + NFTA_RULE_CHAIN_ID, __NFTA_RULE_MAX }; #define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1) @@ -266,8 +295,10 @@ enum nft_rule_compat_attributes { * @NFT_SET_INTERVAL: set contains intervals * @NFT_SET_MAP: set is used as a dictionary * @NFT_SET_TIMEOUT: set uses timeouts - * @NFT_SET_EVAL: set contains expressions for evaluation + * @NFT_SET_EVAL: set can be updated from the evaluation path * @NFT_SET_OBJECT: set contains stateful objects + * @NFT_SET_CONCAT: set contains a concatenation + * @NFT_SET_EXPR: set contains expressions */ enum nft_set_flags { NFT_SET_ANONYMOUS = 0x1, @@ -277,6 +308,8 @@ enum nft_set_flags { NFT_SET_TIMEOUT = 0x10, NFT_SET_EVAL = 0x20, NFT_SET_OBJECT = 0x40, + NFT_SET_CONCAT = 0x80, + NFT_SET_EXPR = 0x100, }; /** @@ -294,14 +327,28 @@ enum nft_set_policies { * enum nft_set_desc_attributes - set element description * * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32) + * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED) */ enum nft_set_desc_attributes { NFTA_SET_DESC_UNSPEC, NFTA_SET_DESC_SIZE, + NFTA_SET_DESC_CONCAT, __NFTA_SET_DESC_MAX }; #define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1) +/** + * enum nft_set_field_attributes - attributes of concatenated fields + * + * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32) + */ +enum nft_set_field_attributes { + NFTA_SET_FIELD_UNSPEC, + NFTA_SET_FIELD_LEN, + __NFTA_SET_FIELD_MAX +}; +#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1) + /** * enum nft_set_attributes - nf_tables set netlink attributes * @@ -320,6 +367,8 @@ enum nft_set_desc_attributes { * @NFTA_SET_USERDATA: user data (NLA_BINARY) * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*) * @NFTA_SET_HANDLE: set handle (NLA_U64) + * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes) + * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_set_attributes { NFTA_SET_UNSPEC, @@ -339,6 +388,8 @@ enum nft_set_attributes { NFTA_SET_PAD, NFTA_SET_OBJ_TYPE, NFTA_SET_HANDLE, + NFTA_SET_EXPR, + NFTA_SET_EXPRESSIONS, __NFTA_SET_MAX }; #define NFTA_SET_MAX (__NFTA_SET_MAX - 1) @@ -347,9 +398,11 @@ enum nft_set_attributes { * enum nft_set_elem_flags - nf_tables set element flags * * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval + * @NFT_SET_ELEM_CATCHALL: special catch-all element */ enum nft_set_elem_flags { NFT_SET_ELEM_INTERVAL_END = 0x1, + NFT_SET_ELEM_CATCHALL = 0x2, }; /** @@ -363,6 +416,8 @@ enum nft_set_elem_flags { * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY) * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes) * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING) + * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data) + * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_set_elem_attributes { NFTA_SET_ELEM_UNSPEC, @@ -375,6 +430,8 @@ enum nft_set_elem_attributes { NFTA_SET_ELEM_EXPR, NFTA_SET_ELEM_PAD, NFTA_SET_ELEM_OBJREF, + NFTA_SET_ELEM_KEY_END, + NFTA_SET_ELEM_EXPRESSIONS, __NFTA_SET_ELEM_MAX }; #define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1) @@ -440,11 +497,13 @@ enum nft_data_attributes { * * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts) * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING) + * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32) */ enum nft_verdict_attributes { NFTA_VERDICT_UNSPEC, NFTA_VERDICT_CODE, NFTA_VERDICT_CHAIN, + NFTA_VERDICT_CHAIN_ID, __NFTA_VERDICT_MAX }; #define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1) @@ -477,6 +536,20 @@ enum nft_immediate_attributes { }; #define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1) +/** + * enum nft_bitwise_ops - nf_tables bitwise operations + * + * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and + * XOR boolean operations + * @NFT_BITWISE_LSHIFT: left-shift operation + * @NFT_BITWISE_RSHIFT: right-shift operation + */ +enum nft_bitwise_ops { + NFT_BITWISE_BOOL, + NFT_BITWISE_LSHIFT, + NFT_BITWISE_RSHIFT, +}; + /** * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes * @@ -485,16 +558,20 @@ enum nft_immediate_attributes { * @NFTA_BITWISE_LEN: length of operands (NLA_U32) * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes) * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) + * @NFTA_BITWISE_DATA: argument for non-boolean operations + * (NLA_NESTED: nft_data_attributes) * - * The bitwise expression performs the following operation: + * The bitwise expression supports boolean and shift operations. It implements + * the boolean operations by performing the following operation: * * dreg = (sreg & mask) ^ xor * - * which allow to express all bitwise operations: + * with these mask and xor values: * * mask xor * NOT: 1 1 - * OR: 0 x + * OR: ~x x * XOR: 1 x * AND: x 0 */ @@ -505,6 +582,8 @@ enum nft_bitwise_attributes { NFTA_BITWISE_LEN, NFTA_BITWISE_MASK, NFTA_BITWISE_XOR, + NFTA_BITWISE_OP, + NFTA_BITWISE_DATA, __NFTA_BITWISE_MAX }; #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) @@ -631,10 +710,12 @@ enum nft_lookup_attributes { enum nft_dynset_ops { NFT_DYNSET_OP_ADD, NFT_DYNSET_OP_UPDATE, + NFT_DYNSET_OP_DELETE, }; enum nft_dynset_flags { NFT_DYNSET_F_INV = (1 << 0), + NFT_DYNSET_F_EXPR = (1 << 1), }; /** @@ -648,6 +729,7 @@ enum nft_dynset_flags { * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64) * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes) * @NFTA_DYNSET_FLAGS: flags (NLA_U32) + * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_dynset_attributes { NFTA_DYNSET_UNSPEC, @@ -660,6 +742,7 @@ enum nft_dynset_attributes { NFTA_DYNSET_EXPR, NFTA_DYNSET_PAD, NFTA_DYNSET_FLAGS, + NFTA_DYNSET_EXPRESSIONS, __NFTA_DYNSET_MAX, }; #define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1) @@ -682,10 +765,12 @@ enum nft_payload_bases { * * @NFT_PAYLOAD_CSUM_NONE: no checksumming * @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791) + * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309) */ enum nft_payload_csum_types { NFT_PAYLOAD_CSUM_NONE, NFT_PAYLOAD_CSUM_INET, + NFT_PAYLOAD_CSUM_SCTP, }; enum nft_payload_csum_flags { @@ -727,10 +812,14 @@ enum nft_exthdr_flags { * * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers * @NFT_EXTHDR_OP_TCP: match against tcp options + * @NFT_EXTHDR_OP_IPV4: match against ipv4 options + * @NFT_EXTHDR_OP_SCTP: match against sctp chunks */ enum nft_exthdr_op { NFT_EXTHDR_OP_IPV6, NFT_EXTHDR_OP_TCPOPT, + NFT_EXTHDR_OP_IPV4, + NFT_EXTHDR_OP_SCTP, __NFT_EXTHDR_OP_MAX }; #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) @@ -788,6 +877,15 @@ enum nft_exthdr_attributes { * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) * @NFT_META_PRANDOM: a 32bit pseudo-random number * @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp) + * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_BRI_IIFPVID: packet input bridge port pvid + * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto + * @NFT_META_TIME_NS: time since epoch (in nanoseconds) + * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday) + * @NFT_META_TIME_HOUR: hour of day (in seconds) + * @NFT_META_SDIF: slave device interface index + * @NFT_META_SDIFNAME: slave device interface name */ enum nft_meta_keys { NFT_META_LEN, @@ -816,6 +914,15 @@ enum nft_meta_keys { NFT_META_CGROUP, NFT_META_PRANDOM, NFT_META_SECPATH, + NFT_META_IIFKIND, + NFT_META_OIFKIND, + NFT_META_BRI_IIFPVID, + NFT_META_BRI_IIFVPROTO, + NFT_META_TIME_NS, + NFT_META_TIME_DAY, + NFT_META_TIME_HOUR, + NFT_META_SDIF, + NFT_META_SDIFNAME, }; /** @@ -825,13 +932,17 @@ enum nft_meta_keys { * @NFT_RT_NEXTHOP4: routing nexthop for IPv4 * @NFT_RT_NEXTHOP6: routing nexthop for IPv6 * @NFT_RT_TCPMSS: fetch current path tcp mss + * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL */ enum nft_rt_keys { NFT_RT_CLASSID, NFT_RT_NEXTHOP4, NFT_RT_NEXTHOP6, NFT_RT_TCPMSS, + NFT_RT_XFRM, + __NFT_RT_MAX }; +#define NFT_RT_MAX (__NFT_RT_MAX - 1) /** * enum nft_hash_types - nf_tables hash expression types @@ -854,6 +965,8 @@ enum nft_hash_types { * @NFTA_HASH_SEED: seed value (NLA_U32) * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32) * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types) + * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_HASH_SET_ID: id of the map (NLA_U32) */ enum nft_hash_attributes { NFTA_HASH_UNSPEC, @@ -864,6 +977,8 @@ enum nft_hash_attributes { NFTA_HASH_SEED, NFTA_HASH_OFFSET, NFTA_HASH_TYPE, + NFTA_HASH_SET_NAME, /* deprecated */ + NFTA_HASH_SET_ID, /* deprecated */ __NFTA_HASH_MAX, }; #define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1) @@ -898,6 +1013,39 @@ enum nft_rt_attributes { }; #define NFTA_RT_MAX (__NFTA_RT_MAX - 1) +/** + * enum nft_socket_attributes - nf_tables socket expression netlink attributes + * + * @NFTA_SOCKET_KEY: socket key to match + * @NFTA_SOCKET_DREG: destination register + * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2) + */ +enum nft_socket_attributes { + NFTA_SOCKET_UNSPEC, + NFTA_SOCKET_KEY, + NFTA_SOCKET_DREG, + NFTA_SOCKET_LEVEL, + __NFTA_SOCKET_MAX +}; +#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) + +/* + * enum nft_socket_keys - nf_tables socket expression keys + * + * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option + * @NFT_SOCKET_MARK: Value of the socket mark + * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) + * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2 + */ +enum nft_socket_keys { + NFT_SOCKET_TRANSPARENT, + NFT_SOCKET_MARK, + NFT_SOCKET_WILDCARD, + NFT_SOCKET_CGROUPV2, + __NFT_SOCKET_MAX +}; +#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) + /** * enum nft_ct_keys - nf_tables ct expression keys * @@ -909,8 +1057,8 @@ enum nft_rt_attributes { * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms * @NFT_CT_HELPER: connection tracking helper assigned to conntrack * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol - * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address) - * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address) + * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated) + * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated) * @NFT_CT_PROTOCOL: conntrack layer 4 protocol * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination @@ -920,6 +1068,11 @@ enum nft_rt_attributes { * @NFT_CT_AVGPKT: conntrack average bytes per packet * @NFT_CT_ZONE: conntrack zone * @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack + * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address) + * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) + * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) + * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) + * @NFT_CT_ID: conntrack id */ enum nft_ct_keys { NFT_CT_STATE, @@ -941,7 +1094,14 @@ enum nft_ct_keys { NFT_CT_AVGPKT, NFT_CT_ZONE, NFT_CT_EVENTMASK, + NFT_CT_SRC_IP, + NFT_CT_DST_IP, + NFT_CT_SRC_IP6, + NFT_CT_DST_IP6, + NFT_CT_ID, + __NFT_CT_MAX }; +#define NFT_CT_MAX (__NFT_CT_MAX - 1) /** * enum nft_ct_attributes - nf_tables ct expression netlink attributes @@ -1002,6 +1162,24 @@ enum nft_limit_attributes { }; #define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1) +enum nft_connlimit_flags { + NFT_CONNLIMIT_F_INV = (1 << 0), +}; + +/** + * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes + * + * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32) + * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags) + */ +enum nft_connlimit_attributes { + NFTA_CONNLIMIT_UNSPEC, + NFTA_CONNLIMIT_COUNT, + NFTA_CONNLIMIT_FLAGS, + __NFTA_CONNLIMIT_MAX +}; +#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1) + /** * enum nft_counter_attributes - nf_tables counter expression netlink attributes * @@ -1017,6 +1195,21 @@ enum nft_counter_attributes { }; #define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1) +/** + * enum nft_last_attributes - nf_tables last expression netlink attributes + * + * @NFTA_LAST_SET: last update has been set, zero means never updated (NLA_U32) + * @NFTA_LAST_MSECS: milliseconds since last update (NLA_U64) + */ +enum nft_last_attributes { + NFTA_LAST_UNSPEC, + NFTA_LAST_SET, + NFTA_LAST_MSECS, + NFTA_LAST_PAD, + __NFTA_LAST_MAX +}; +#define NFTA_LAST_MAX (__NFTA_LAST_MAX - 1) + /** * enum nft_log_attributes - nf_tables log expression netlink attributes * @@ -1039,6 +1232,33 @@ enum nft_log_attributes { }; #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) +/** + * enum nft_log_level - nf_tables log levels + * + * @NFT_LOGLEVEL_EMERG: system is unusable + * @NFT_LOGLEVEL_ALERT: action must be taken immediately + * @NFT_LOGLEVEL_CRIT: critical conditions + * @NFT_LOGLEVEL_ERR: error conditions + * @NFT_LOGLEVEL_WARNING: warning conditions + * @NFT_LOGLEVEL_NOTICE: normal but significant condition + * @NFT_LOGLEVEL_INFO: informational + * @NFT_LOGLEVEL_DEBUG: debug-level messages + * @NFT_LOGLEVEL_AUDIT: enabling audit logging + */ +enum nft_log_level { + NFT_LOGLEVEL_EMERG, + NFT_LOGLEVEL_ALERT, + NFT_LOGLEVEL_CRIT, + NFT_LOGLEVEL_ERR, + NFT_LOGLEVEL_WARNING, + NFT_LOGLEVEL_NOTICE, + NFT_LOGLEVEL_INFO, + NFT_LOGLEVEL_DEBUG, + NFT_LOGLEVEL_AUDIT, + __NFT_LOGLEVEL_MAX +}; +#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1) + /** * enum nft_queue_attributes - nf_tables queue expression netlink attributes * @@ -1083,6 +1303,21 @@ enum nft_quota_attributes { }; #define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1) +/** + * enum nft_secmark_attributes - nf_tables secmark object netlink attributes + * + * @NFTA_SECMARK_CTX: security context (NLA_STRING) + */ +enum nft_secmark_attributes { + NFTA_SECMARK_UNSPEC, + NFTA_SECMARK_CTX, + __NFTA_SECMARK_MAX, +}; +#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1) + +/* Max security context length */ +#define NFT_SECMARK_CTX_MAXLEN 256 + /** * enum nft_reject_types - nf_tables reject expression reject types * @@ -1164,6 +1399,22 @@ enum nft_nat_attributes { }; #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) +/** + * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes + * + * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers) + */ +enum nft_tproxy_attributes { + NFTA_TPROXY_UNSPEC, + NFTA_TPROXY_FAMILY, + NFTA_TPROXY_REG_ADDR, + NFTA_TPROXY_REG_PORT, + __NFTA_TPROXY_MAX +}; +#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1) + /** * enum nft_masq_attributes - nf_tables masquerade expression attributes * @@ -1214,10 +1465,14 @@ enum nft_dup_attributes { * enum nft_fwd_attributes - nf_tables fwd expression netlink attributes * * @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register) + * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register) + * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto) */ enum nft_fwd_attributes { NFTA_FWD_UNSPEC, NFTA_FWD_SREG_DEV, + NFTA_FWD_SREG_ADDR, + NFTA_FWD_NFPROTO, __NFTA_FWD_MAX }; #define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1) @@ -1302,12 +1557,38 @@ enum nft_ct_helper_attributes { }; #define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) +enum nft_ct_timeout_timeout_attributes { + NFTA_CT_TIMEOUT_UNSPEC, + NFTA_CT_TIMEOUT_L3PROTO, + NFTA_CT_TIMEOUT_L4PROTO, + NFTA_CT_TIMEOUT_DATA, + __NFTA_CT_TIMEOUT_MAX, +}; +#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) + +enum nft_ct_expectation_attributes { + NFTA_CT_EXPECT_UNSPEC, + NFTA_CT_EXPECT_L3PROTO, + NFTA_CT_EXPECT_L4PROTO, + NFTA_CT_EXPECT_DPORT, + NFTA_CT_EXPECT_TIMEOUT, + NFTA_CT_EXPECT_SIZE, + __NFTA_CT_EXPECT_MAX, +}; +#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1) + #define NFT_OBJECT_UNSPEC 0 #define NFT_OBJECT_COUNTER 1 #define NFT_OBJECT_QUOTA 2 #define NFT_OBJECT_CT_HELPER 3 #define NFT_OBJECT_LIMIT 4 -#define __NFT_OBJECT_MAX 5 +#define NFT_OBJECT_CONNLIMIT 5 +#define NFT_OBJECT_TUNNEL 6 +#define NFT_OBJECT_CT_TIMEOUT 7 +#define NFT_OBJECT_SECMARK 8 +#define NFT_OBJECT_CT_EXPECT 9 +#define NFT_OBJECT_SYNPROXY 10 +#define __NFT_OBJECT_MAX 11 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) /** @@ -1319,6 +1600,7 @@ enum nft_ct_helper_attributes { * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED) * @NFTA_OBJ_USE: number of references to this expression (NLA_U32) * @NFTA_OBJ_HANDLE: object handle (NLA_U64) + * @NFTA_OBJ_USERDATA: user data (NLA_BINARY) */ enum nft_object_attributes { NFTA_OBJ_UNSPEC, @@ -1329,10 +1611,24 @@ enum nft_object_attributes { NFTA_OBJ_USE, NFTA_OBJ_HANDLE, NFTA_OBJ_PAD, + NFTA_OBJ_USERDATA, __NFTA_OBJ_MAX }; #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) +/** + * enum nft_flowtable_flags - nf_tables flowtable flags + * + * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled + * @NFT_FLOWTABLE_COUNTER: enable flow counters + */ +enum nft_flowtable_flags { + NFT_FLOWTABLE_HW_OFFLOAD = 0x1, + NFT_FLOWTABLE_COUNTER = 0x2, + NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD | + NFT_FLOWTABLE_COUNTER) +}; + /** * enum nft_flowtable_attributes - nf_tables flow table netlink attributes * @@ -1341,6 +1637,7 @@ enum nft_object_attributes { * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32) * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32) * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64) + * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32) */ enum nft_flowtable_attributes { NFTA_FLOWTABLE_UNSPEC, @@ -1350,6 +1647,7 @@ enum nft_flowtable_attributes { NFTA_FLOWTABLE_USE, NFTA_FLOWTABLE_HANDLE, NFTA_FLOWTABLE_PAD, + NFTA_FLOWTABLE_FLAGS, __NFTA_FLOWTABLE_MAX }; #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1) @@ -1370,6 +1668,42 @@ enum nft_flowtable_hook_attributes { }; #define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) +/** + * enum nft_osf_attributes - nftables osf expression netlink attributes + * + * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8) + * @NFTA_OSF_FLAGS: flags (NLA_U32) + */ +enum nft_osf_attributes { + NFTA_OSF_UNSPEC, + NFTA_OSF_DREG, + NFTA_OSF_TTL, + NFTA_OSF_FLAGS, + __NFTA_OSF_MAX, +}; +#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) + +enum nft_osf_flags { + NFT_OSF_F_VERSION = (1 << 0), +}; + +/** + * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes + * + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16) + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8) + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32) + */ +enum nft_synproxy_attributes { + NFTA_SYNPROXY_UNSPEC, + NFTA_SYNPROXY_MSS, + NFTA_SYNPROXY_WSCALE, + NFTA_SYNPROXY_FLAGS, + __NFTA_SYNPROXY_MAX, +}; +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1) + /** * enum nft_device_attributes - nf_tables device netlink attributes * @@ -1382,6 +1716,35 @@ enum nft_devices_attributes { }; #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1) +/* + * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes + * + * @NFTA_XFRM_DREG: destination register (NLA_U32) + * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32) + * @NFTA_XFRM_DIR: direction (NLA_U8) + * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32) + */ +enum nft_xfrm_attributes { + NFTA_XFRM_UNSPEC, + NFTA_XFRM_DREG, + NFTA_XFRM_KEY, + NFTA_XFRM_DIR, + NFTA_XFRM_SPNUM, + __NFTA_XFRM_MAX +}; +#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1) + +enum nft_xfrm_keys { + NFT_XFRM_KEY_UNSPEC, + NFT_XFRM_KEY_DADDR_IP4, + NFT_XFRM_KEY_DADDR_IP6, + NFT_XFRM_KEY_SADDR_IP4, + NFT_XFRM_KEY_SADDR_IP6, + NFT_XFRM_KEY_REQID, + NFT_XFRM_KEY_SPI, + __NFT_XFRM_KEY_MAX, +}; +#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1) /** * enum nft_trace_attributes - nf_tables trace netlink attributes @@ -1442,6 +1805,8 @@ enum nft_trace_types { * @NFTA_NG_MODULUS: maximum counter value (NLA_U32) * @NFTA_NG_TYPE: operation type (NLA_U32) * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32) + * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_NG_SET_ID: id of the map (NLA_U32) */ enum nft_ng_attributes { NFTA_NG_UNSPEC, @@ -1449,6 +1814,8 @@ enum nft_ng_attributes { NFTA_NG_MODULUS, NFTA_NG_TYPE, NFTA_NG_OFFSET, + NFTA_NG_SET_NAME, /* deprecated */ + NFTA_NG_SET_ID, /* deprecated */ __NFTA_NG_MAX }; #define NFTA_NG_MAX (__NFTA_NG_MAX - 1) @@ -1460,4 +1827,104 @@ enum nft_ng_types { }; #define NFT_NG_MAX (__NFT_NG_MAX - 1) +enum nft_tunnel_key_ip_attributes { + NFTA_TUNNEL_KEY_IP_UNSPEC, + NFTA_TUNNEL_KEY_IP_SRC, + NFTA_TUNNEL_KEY_IP_DST, + __NFTA_TUNNEL_KEY_IP_MAX +}; +#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1) + +enum nft_tunnel_ip6_attributes { + NFTA_TUNNEL_KEY_IP6_UNSPEC, + NFTA_TUNNEL_KEY_IP6_SRC, + NFTA_TUNNEL_KEY_IP6_DST, + NFTA_TUNNEL_KEY_IP6_FLOWLABEL, + __NFTA_TUNNEL_KEY_IP6_MAX +}; +#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1) + +enum nft_tunnel_opts_attributes { + NFTA_TUNNEL_KEY_OPTS_UNSPEC, + NFTA_TUNNEL_KEY_OPTS_VXLAN, + NFTA_TUNNEL_KEY_OPTS_ERSPAN, + NFTA_TUNNEL_KEY_OPTS_GENEVE, + __NFTA_TUNNEL_KEY_OPTS_MAX +}; +#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1) + +enum nft_tunnel_opts_vxlan_attributes { + NFTA_TUNNEL_KEY_VXLAN_UNSPEC, + NFTA_TUNNEL_KEY_VXLAN_GBP, + __NFTA_TUNNEL_KEY_VXLAN_MAX +}; +#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1) + +enum nft_tunnel_opts_erspan_attributes { + NFTA_TUNNEL_KEY_ERSPAN_UNSPEC, + NFTA_TUNNEL_KEY_ERSPAN_VERSION, + NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, + NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, + NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, + __NFTA_TUNNEL_KEY_ERSPAN_MAX +}; +#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1) + +enum nft_tunnel_opts_geneve_attributes { + NFTA_TUNNEL_KEY_GENEVE_UNSPEC, + NFTA_TUNNEL_KEY_GENEVE_CLASS, + NFTA_TUNNEL_KEY_GENEVE_TYPE, + NFTA_TUNNEL_KEY_GENEVE_DATA, + __NFTA_TUNNEL_KEY_GENEVE_MAX +}; +#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1) + +enum nft_tunnel_flags { + NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0), + NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1), + NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2), +}; +#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \ + NFT_TUNNEL_F_DONT_FRAGMENT | \ + NFT_TUNNEL_F_SEQ_NUMBER) + +enum nft_tunnel_key_attributes { + NFTA_TUNNEL_KEY_UNSPEC, + NFTA_TUNNEL_KEY_ID, + NFTA_TUNNEL_KEY_IP, + NFTA_TUNNEL_KEY_IP6, + NFTA_TUNNEL_KEY_FLAGS, + NFTA_TUNNEL_KEY_TOS, + NFTA_TUNNEL_KEY_TTL, + NFTA_TUNNEL_KEY_SPORT, + NFTA_TUNNEL_KEY_DPORT, + NFTA_TUNNEL_KEY_OPTS, + __NFTA_TUNNEL_KEY_MAX +}; +#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1) + +enum nft_tunnel_keys { + NFT_TUNNEL_PATH, + NFT_TUNNEL_ID, + __NFT_TUNNEL_MAX +}; +#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1) + +enum nft_tunnel_mode { + NFT_TUNNEL_MODE_NONE, + NFT_TUNNEL_MODE_RX, + NFT_TUNNEL_MODE_TX, + __NFT_TUNNEL_MODE_MAX +}; +#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1) + +enum nft_tunnel_attributes { + NFTA_TUNNEL_UNSPEC, + NFTA_TUNNEL_KEY, + NFTA_TUNNEL_DREG, + NFTA_TUNNEL_MODE, + __NFTA_TUNNEL_MAX +}; +#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1) + #endif /* _LINUX_NF_TABLES_H */ diff --git a/iptables/nft.c b/iptables/nft.c index f31c1603..61b56c91 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1170,7 +1170,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table, type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR; len += sizeof(struct in_addr) + NETLINK_ALIGN - 1; len &= ~(NETLINK_ALIGN - 1); - flags = NFT_SET_INTERVAL; + flags = NFT_SET_INTERVAL | NFT_SET_CONCAT; } s = add_anon_set(h, table, flags, type, len, cnt); -- cgit v1.2.3 From dccccdff1f6d37a2f1fdbc4ef22f2a97bf0cf1a6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 22 Sep 2022 16:14:51 +0200 Subject: Revert "nft: prefer payload to ttl/hl module"/'meta pkttype' match. This reverts commit 8acaccf69c22fb195a0b88e28489792304728245. This reverts commit 793caef9076cceb24336b6cbb8f55107de49f269. As per ongoing discussion, keep the dissection side but keep using nft_compat mode for now until we've figured out how to handle backwards compatibility with older iptables-nft binaries dumping the ruleset. Furthermore, "nft: prefer native 'meta pkttype' instead of xt match" broke ebtables: it has its own, incompatible pkttype match and needs special handling. Signed-off-by: Florian Westphal --- iptables/nft.c | 65 ---------------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 61b56c91..2165733f 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -41,9 +41,6 @@ #include #include #include -#include - -#include #include #include @@ -1448,60 +1445,6 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, return 0; } -static int add_nft_pkttype(struct nft_handle *h, struct nftnl_rule *r, - struct xt_entry_match *m) -{ - struct xt_pkttype_info *pkti = (void *)m->data; - uint8_t reg; - int op; - - add_meta(h, r, NFT_META_PKTTYPE, ®); - - if (pkti->invert) - op = NFT_CMP_NEQ; - else - op = NFT_CMP_EQ; - - add_cmp_u8(r, pkti->pkttype, op, reg); - - return 0; -} - -static int add_nft_hl(struct nft_handle *h, struct nftnl_rule *r, - struct xt_entry_match *m, uint8_t offset) -{ - struct ip6t_hl_info *info = (void *)m->data; - struct nftnl_expr *expr; - uint8_t reg; - uint8_t op; - - switch (info->mode) { - case IP6T_HL_NE: - op = NFT_CMP_NEQ; - break; - case IP6T_HL_EQ: - op = NFT_CMP_EQ; - break; - case IP6T_HL_LT: - op = NFT_CMP_LT; - break; - case IP6T_HL_GT: - op = NFT_CMP_GT; - break; - default: - return -EINVAL; - } - - expr = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, offset, 1, ®); - if (!expr) - return -ENOMEM; - - nftnl_rule_add_expr(r, expr); - add_cmp_u8(r, info->hop_limit, op, reg); - - return 0; -} - int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { @@ -1518,14 +1461,6 @@ int add_match(struct nft_handle *h, return add_nft_tcp(h, r, m); else if (!strcmp(m->u.user.name, "mark")) return add_nft_mark(h, r, m); - else if (!strcmp(m->u.user.name, "pkttype")) - return add_nft_pkttype(h, r, m); - else if (!strcmp(m->u.user.name, "hl")) - return add_nft_hl(h, r, m, - offsetof(struct ip6_hdr, ip6_hlim)); - else if (!strcmp(m->u.user.name, "ttl")) - return add_nft_hl(h, r, m, - offsetof(struct iphdr, ttl)); expr = nftnl_expr_alloc("match"); if (expr == NULL) -- cgit v1.2.3 From d1aa01483b5cac8c70c9385033e60efd7a744e1f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 22 Sep 2022 19:04:32 +0200 Subject: tests: shell: Test delinearization of native nftables expressions Even if iptables-nft doesn't generate them anymore, it should continue to correctly parse them. Make sure this is tested for. Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- .../testcases/nft-only/0010-native-delinearize_0 | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 diff --git a/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 new file mode 100755 index 00000000..cca36fd8 --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 @@ -0,0 +1,26 @@ +#!/bin/bash + +[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } +nft -v >/dev/null || exit 0 + +set -e + +nft -f - < Date: Fri, 23 Sep 2022 14:17:08 +0200 Subject: nft: track each register individually Instead of assuming only one register is used, track all 16 regs individually. This avoids need for the 'PREV_PAYLOAD' hack and also avoids the need to clear out old flags: When we see that register 'x' will be written to, that register state is reset automatically. Existing dissector decodes ip saddr 1.2.3.4 meta l4proto tcp ... as -s 6.0.0.0 -p tcp iptables-nft -s 1.2.3.4 -p tcp is decoded correctly because the expressions are ordered like: meta l4proto tcp ip saddr 1.2.3.4 | ... and 'meta l4proto' did clear the PAYLOAD flag. The simpler fix is: ctx->flags &= ~NFT_XT_CTX_PAYLOAD; in nft_parse_cmp(), but that breaks dissection of '1-42', because the second compare ('cmp lte 42') will not find the payload expression anymore. Link: https://lore.kernel.org/netfilter-devel/20220922143544.GA22541@breakpoint.cc/T/#t Signed-off-by: Florian Westphal Reviewed-by: Phil Sutter --- iptables/nft-arp.c | 57 +++++++------- iptables/nft-bridge.c | 102 +++++++++++++++---------- iptables/nft-ipv4.c | 49 ++++++------ iptables/nft-ipv6.c | 36 ++++----- iptables/nft-shared.c | 205 +++++++++++++++++++++++++++++++++++--------------- iptables/nft-shared.h | 110 ++++++++++++++++++++------- 6 files changed, 360 insertions(+), 199 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index e6e4d2d8..e9e11141 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -160,25 +160,27 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, return ret; } -static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, +static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, struct iptables_command_state *cs) { struct arpt_entry *fw = &cs->arp; uint8_t flags = 0; - parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, + parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, fw->arp.outiface, fw->arp.outiface_mask, &flags); fw->arp.invflags |= flags; } -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) { - mask->s_addr = ctx->bitwise.mask[0]; + mask->s_addr = reg->bitwise.mask[0]; } -static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, +static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct arpt_devaddr_info *info) { @@ -192,18 +194,17 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, get_cmp_data(e, info->addr, ETH_ALEN, &inv); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); + else memset(info->mask, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); return inv; } static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -213,7 +214,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, uint8_t ar_hln; bool inv; - switch (ctx->payload.offset) { + switch (reg->payload.offset) { case offsetof(struct arphdr, ar_hrd): get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); fw->arp.arhrd = ar_hrd; @@ -243,43 +244,39 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, fw->arp.invflags |= IPT_INV_ARPOP; break; default: - if (ctx->payload.offset == sizeof(struct arphdr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr)) + if (reg->payload.offset == sizeof(struct arphdr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) fw->arp.invflags |= IPT_INV_SRCDEVADDR; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln) { get_cmp_data(e, &addr, sizeof(addr), &inv); fw->arp.src.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.smsk); + else memset(&fw->arp.smsk, 0xff, - min(ctx->payload.len, + min(reg->payload.len, sizeof(struct in_addr))); - } if (inv) fw->arp.invflags |= IPT_INV_SRCIP; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr)) + if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) fw->arp.invflags |= IPT_INV_TGTDEVADDR; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln) { get_cmp_data(e, &addr, sizeof(addr), &inv); fw->arp.tgt.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.tmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.tmsk); + else memset(&fw->arp.tmsk, 0xff, - min(ctx->payload.len, + min(reg->payload.len, sizeof(struct in_addr))); - } if (inv) fw->arp.invflags |= IPT_INV_DSTIP; diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 106bcc72..1121e864 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -170,6 +170,7 @@ static int nft_bridge_add(struct nft_handle *h, } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -177,9 +178,9 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); + parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags); - switch (ctx->meta.key) { + switch (reg->meta_dreg.key) { case NFT_META_BRI_IIFNAME: if (invflags & IPT_INV_VIA_IN) cs->eb.invflags |= EBT_ILOGICALIN; @@ -206,6 +207,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, } static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -215,7 +217,7 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, bool inv; int i; - switch (ctx->payload.offset) { + switch (reg->payload.offset) { case offsetof(struct ethhdr, h_dest): get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) @@ -223,13 +225,11 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, if (inv) fw->invflags |= EBT_IDEST; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); + else memset(&fw->destmsk, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); fw->bitmask |= EBT_IDEST; break; case offsetof(struct ethhdr, h_source): @@ -238,13 +238,11 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, fw->sourcemac[i] = addr[i]; if (inv) fw->invflags |= EBT_ISOURCE; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); + else memset(&fw->sourcemsk, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); fw->bitmask |= EBT_ISOURCE; break; case offsetof(struct ethhdr, h_proto): @@ -294,28 +292,53 @@ lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) /* Make sure previous payload expression(s) is/are consistent and extract if * matching on source or destination address and if matching on MAC and IP or * only MAC address. */ -static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx, +static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, + enum nft_registers sreg, + uint32_t key_len, bool *dst, bool *ip) { + const struct nft_xt_ctx_reg *reg; + uint32_t sreg_count; int val, val2 = -1; - if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) { - val = lookup_check_ether_payload(ctx->prev_payload.base, - ctx->prev_payload.offset, - ctx->prev_payload.len); + reg = nft_xt_ctx_get_sreg(ctx, sreg); + if (!reg) + return -1; + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "lookup reg is not payload type"; + return -1; + } + + sreg_count = sreg; + switch (key_len) { + case 12: /* ether + ipv4addr */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->prev_payload.base, ctx->prev_payload.offset, - ctx->prev_payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } - if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) { - DEBUGP("Previous but no current payload?\n"); + + sreg_count += 2; + + reg = nft_xt_ctx_get_sreg(ctx, sreg_count); + if (!reg) { + ctx->errmsg = "next lookup register is invalid"; + return -1; + } + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "next lookup reg is not payload type"; return -1; } - val2 = lookup_check_iphdr_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); + + val2 = lookup_check_iphdr_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val2 < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", ctx->payload.base, ctx->payload.offset, @@ -325,18 +348,20 @@ static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx, DEBUGP("mismatching payload match offsets\n"); return -1; } - } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - val = lookup_check_ether_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); + break; + case 4: /* ipv4addr */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", ctx->payload.base, ctx->payload.offset, ctx->payload.len); return -1; } - } else { - DEBUGP("unknown LHS of lookup expression\n"); + break; + default: + ctx->errmsg = "unsupported lookup key length"; return -1; } @@ -413,14 +438,17 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, size_t poff, size; uint32_t cnt; - if (lookup_analyze_payloads(ctx, &is_dst, &have_ip)) - return; - s = set_from_lookup_expr(ctx, e); if (!s) xtables_error(OTHER_PROBLEM, "BUG: lookup expression references unknown set"); + if (lookup_analyze_payloads(ctx, + nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), + nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), + &is_dst, &have_ip)) + return; + cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { @@ -468,8 +496,6 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) xtables_error(OTHER_PROBLEM, "ebtables among pair parsing failed"); - - ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD); } static void parse_watcher(void *object, struct ebt_match **match_list, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 1865d151..92a914f1 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -115,28 +115,28 @@ static bool nft_ipv4_is_same(const struct iptables_command_state *a, b->fw.ip.iniface_mask, b->fw.ip.outiface_mask); } -static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) +static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e) { uint8_t op; /* we assume correct mask and xor */ - if (!(ctx->flags & NFT_XT_CTX_BITWISE)) - return; + if (!reg->bitwise.set) + return false; /* we assume correct data */ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); if (op == NFT_CMP_EQ) - *inv = true; - else - *inv = false; + return true; - ctx->flags &= ~NFT_XT_CTX_BITWISE; + return false; } -static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, +static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, struct iptables_command_state *cs) { - switch (ctx->meta.key) { + switch (reg->meta_dreg.key) { case NFT_META_L4PROTO: cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) @@ -146,17 +146,18 @@ static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, break; } - parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, cs->fw.ip.outiface, cs->fw.ip.outiface_mask, &cs->fw.ip.invflags); } -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) { - mask->s_addr = ctx->bitwise.mask[0]; + mask->s_addr = sreg->bitwise.mask[0]; } static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -164,16 +165,15 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, uint8_t proto; bool inv; - switch(ctx->payload.offset) { + switch (sreg->payload.offset) { case offsetof(struct iphdr, saddr): get_cmp_data(e, &addr, sizeof(addr), &inv); cs->fw.ip.src.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &cs->fw.ip.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; + if (sreg->bitwise.set) { + parse_mask_ipv4(sreg, &cs->fw.ip.smsk); } else { memset(&cs->fw.ip.smsk, 0xff, - min(ctx->payload.len, sizeof(struct in_addr))); + min(sreg->payload.len, sizeof(struct in_addr))); } if (inv) @@ -182,13 +182,11 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, case offsetof(struct iphdr, daddr): get_cmp_data(e, &addr, sizeof(addr), &inv); cs->fw.ip.dst.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &cs->fw.ip.dmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (sreg->bitwise.set) + parse_mask_ipv4(sreg, &cs->fw.ip.dmsk); + else memset(&cs->fw.ip.dmsk, 0xff, - min(ctx->payload.len, sizeof(struct in_addr))); - } + min(sreg->payload.len, sizeof(struct in_addr))); if (inv) cs->fw.ip.invflags |= IPT_INV_DSTIP; @@ -201,8 +199,7 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, break; case offsetof(struct iphdr, frag_off): cs->fw.ip.flags |= IPT_F_FRAG; - inv = false; - get_frag(ctx, e, &inv); + inv = get_frag(sreg, e); if (inv) cs->fw.ip.invflags |= IPT_INV_FRAG; break; @@ -210,7 +207,7 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, nft_parse_hl(ctx, e, cs); break; default: - DEBUGP("unknown payload offset %d\n", ctx->payload.offset); + DEBUGP("unknown payload offset %d\n", sreg->payload.offset); break; } } diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 0ab1f971..05d65fbb 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -104,10 +104,12 @@ static bool nft_ipv6_is_same(const struct iptables_command_state *a, b->fw6.ipv6.outiface_mask); } -static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, +static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, struct iptables_command_state *cs) { - switch (ctx->meta.key) { + switch (reg->meta_dreg.key) { case NFT_META_L4PROTO: cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) @@ -117,17 +119,19 @@ static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, break; } - parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface, + parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); } -static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask) +static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, + struct in6_addr *mask) { - memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr)); + memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); } static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -135,17 +139,15 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, uint8_t proto; bool inv; - switch (ctx->payload.offset) { + switch (reg->payload.offset) { case offsetof(struct ip6_hdr, ip6_src): get_cmp_data(e, &addr, sizeof(addr), &inv); memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); + else memset(&cs->fw6.ipv6.smsk, 0xff, - min(ctx->payload.len, sizeof(struct in6_addr))); - } + min(reg->payload.len, sizeof(struct in6_addr))); if (inv) cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; @@ -153,13 +155,11 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, case offsetof(struct ip6_hdr, ip6_dst): get_cmp_data(e, &addr, sizeof(addr), &inv); memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); + else memset(&cs->fw6.ipv6.dmsk, 0xff, - min(ctx->payload.len, sizeof(struct in6_addr))); - } + min(reg->payload.len, sizeof(struct in6_addr))); if (inv) cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 71e2f18d..555f74f0 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -299,6 +299,16 @@ nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name); +static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) +{ + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg); + + if (reg->bitwise.set) + return reg->bitwise.mask[0]; + + return ~0u; +} + static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { struct xt_mark_mtinfo1 *mark; @@ -316,12 +326,7 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); mark->mark = value; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask)); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - mark->mask = 0xffffffff; - } + mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG)); return 0; } @@ -479,20 +484,40 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) *inv = false; } -static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) +static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) { struct xtables_target *target; + struct nft_xt_ctx_reg *sreg; + enum nft_registers sregnum; struct xt_entry_target *t; unsigned int size; const char *targname; - switch (ctx->meta.key) { + sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + if (!sreg) + return; + + if (sreg->meta_sreg.set == 0) + return; + + switch (sreg->meta_sreg.key) { case NFT_META_NFTRACE: - if (ctx->immediate.data[0] == 0) + if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { + ctx->errmsg = "meta nftrace but reg not immediate"; return; + } + + if (sreg->immediate.data[0] == 0) { + ctx->errmsg = "trace is cleared"; + return; + } + targname = "TRACE"; break; default: + ctx->errmsg = "meta sreg key not supported"; return; } @@ -514,51 +539,74 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) 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); + struct nft_xt_ctx_reg *reg; - if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) && - (ctx->flags & NFT_XT_CTX_IMMEDIATE) && - nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) { - ctx->flags &= ~NFT_XT_CTX_IMMEDIATE; - nft_meta_set_to_target(ctx); + if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { + nft_meta_set_to_target(ctx, e); return; } - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); - ctx->flags |= NFT_XT_CTX_META; + reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG)); + if (!reg) + return; + + reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); + reg->type = NFT_XT_REG_META_DREG; } static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - memcpy(&ctx->prev_payload, &ctx->payload, - sizeof(ctx->prev_payload)); - ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD; - } + enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum); - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); - ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); - ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); - ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); - ctx->flags |= NFT_XT_CTX_PAYLOAD; + if (!reg) + return; + + reg->type = NFT_XT_REG_PAYLOAD; + reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); + reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); + reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); } static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { - uint32_t reg, len; + enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); + enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); + struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + struct nft_xt_ctx_reg *dreg = sreg; const void *data; + uint32_t len; - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); - if (ctx->reg && reg != ctx->reg) + if (!sreg) return; - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); - ctx->reg = reg; + if (sregnum != dregnum) { + dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */ + if (!dreg) + return; + + *dreg = *sreg; /* .. and copy content instead */ + } + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); - memcpy(ctx->bitwise.xor, data, len); + + if (len > sizeof(dreg->bitwise.xor)) { + ctx->errmsg = "bitwise xor too large"; + return; + } + + memcpy(dreg->bitwise.xor, data, len); + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); - memcpy(ctx->bitwise.mask, data, len); - ctx->flags |= NFT_XT_CTX_BITWISE; + + if (len > sizeof(dreg->bitwise.mask)) { + ctx->errmsg = "bitwise mask too large"; + return; + } + + memcpy(dreg->bitwise.mask, data, len); + + dreg->bitwise.set = true; } static struct xtables_match * @@ -863,6 +911,8 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs) { + struct nft_xt_ctx_reg *sreg; + enum nft_registers reg; uint32_t sdport; uint16_t port; uint8_t proto, op; @@ -883,7 +933,17 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - switch(ctx->payload.offset) { + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) + return; + + if (sreg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "sgreg not payload"; + return; + } + + switch(sreg->payload.offset) { case 0: /* th->sport */ switch (len) { case 2: /* load sport only */ @@ -909,10 +969,9 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); uint8_t mask = ~0; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(&mask, &ctx->bitwise.mask, sizeof(mask)); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } + if (sreg->bitwise.set) + memcpy(&mask, &sreg->bitwise.mask, sizeof(mask)); + nft_parse_tcp_flags(ctx, cs, op, flags, mask); } return; @@ -920,6 +979,7 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, } static void nft_parse_transport_range(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, struct nftnl_expr *e, struct iptables_command_state *cs) { @@ -949,7 +1009,7 @@ static void nft_parse_transport_range(struct nft_xt_ctx *ctx, from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); - switch(ctx->payload.offset) { + switch (sreg->payload.offset) { case 0: nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); return; @@ -962,30 +1022,40 @@ static void nft_parse_transport_range(struct nft_xt_ctx *ctx, static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { + struct nft_xt_ctx_reg *sreg; uint32_t reg; reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); - if (ctx->reg && reg != ctx->reg) + + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) return; - if (ctx->flags & NFT_XT_CTX_META) { - ctx->h->ops->parse_meta(ctx, e, ctx->cs); - ctx->flags &= ~NFT_XT_CTX_META; - } - /* bitwise context is interpreted from payload */ - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - switch (ctx->payload.base) { + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "cmp sreg undef"; + break; + case NFT_XT_REG_META_DREG: + ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs); + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { case NFT_PAYLOAD_LL_HEADER: if (ctx->h->family == NFPROTO_BRIDGE) - ctx->h->ops->parse_payload(ctx, e, ctx->cs); + ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); break; case NFT_PAYLOAD_NETWORK_HEADER: - ctx->h->ops->parse_payload(ctx, e, ctx->cs); + ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); break; case NFT_PAYLOAD_TRANSPORT_HEADER: nft_parse_transport(ctx, e, ctx->cs); break; } + + break; + default: + ctx->errmsg = "cmp sreg has unknown type"; + break; } } @@ -1004,18 +1074,22 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) int verdict; if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { + struct nft_xt_ctx_reg *dreg; const void *imm_data; uint32_t len; imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len); + dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); + if (!dreg) + return; - if (len > sizeof(ctx->immediate.data)) + if (len > sizeof(dreg->immediate.data)) return; - memcpy(ctx->immediate.data, imm_data, len); - ctx->immediate.len = len; - ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG); - ctx->flags |= NFT_XT_CTX_IMMEDIATE; + memcpy(dreg->immediate.data, imm_data, len); + dreg->immediate.len = len; + dreg->type = NFT_XT_REG_IMMEDIATE; + return; } @@ -1152,20 +1226,29 @@ static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { + struct nft_xt_ctx_reg *sreg; uint32_t reg; reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); - if (reg != ctx->reg) - return; + sreg = nft_xt_ctx_get_sreg(ctx, reg); - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - switch (ctx->payload.base) { + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "range sreg undef"; + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport_range(ctx, e, ctx->cs); + nft_parse_transport_range(ctx, sreg, e, ctx->cs); break; default: + ctx->errmsg = "range with unknown payload base"; break; } + break; + default: + ctx->errmsg = "range sreg type unsupported"; + break; } } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0718dc23..42170638 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -38,13 +38,41 @@ struct xtables_args; struct nft_handle; struct xt_xlate; -enum { - NFT_XT_CTX_PAYLOAD = (1 << 0), - NFT_XT_CTX_META = (1 << 1), - NFT_XT_CTX_BITWISE = (1 << 2), - NFT_XT_CTX_IMMEDIATE = (1 << 3), - NFT_XT_CTX_PREV_PAYLOAD = (1 << 4), - NFT_XT_CTX_RANGE = (1 << 5), +enum nft_ctx_reg_type { + NFT_XT_REG_UNDEF, + NFT_XT_REG_PAYLOAD, + NFT_XT_REG_IMMEDIATE, + NFT_XT_REG_META_DREG, +}; + +struct nft_xt_ctx_reg { + enum nft_ctx_reg_type type:8; + + union { + struct { + uint32_t base; + uint32_t offset; + uint32_t len; + } payload; + struct { + uint32_t data[4]; + uint8_t len; + } immediate; + struct { + uint32_t key; + } meta_dreg; + }; + + struct { + uint32_t mask[4]; + uint32_t xor[4]; + bool set; + } bitwise; + + struct { + uint32_t key; + bool set; + } meta_sreg; }; struct nft_xt_ctx { @@ -58,25 +86,51 @@ struct nft_xt_ctx { struct xt_udp *udp; } tcpudp; - uint32_t reg; - struct { - uint32_t base; - uint32_t offset; - uint32_t len; - } payload, prev_payload; - struct { - uint32_t key; - } meta; - struct { - uint32_t data[4]; - uint32_t len, reg; - } immediate; - struct { - uint32_t mask[4]; - uint32_t xor[4]; - } bitwise; + struct nft_xt_ctx_reg regs[1 + 16]; + + const char *errmsg; }; +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + switch (reg) { + case NFT_REG_VERDICT: + return &ctx->regs[0]; + case NFT_REG_1: + return &ctx->regs[1]; + case NFT_REG_2: + return &ctx->regs[5]; + case NFT_REG_3: + return &ctx->regs[9]; + case NFT_REG_4: + return &ctx->regs[13]; + case NFT_REG32_00...NFT_REG32_15: + return &ctx->regs[reg - NFT_REG32_00]; + default: + ctx->errmsg = "Unknown register requested"; + break; + } + + return NULL; +} + +static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) +{ + r->type = 0; + r->bitwise.set = false; + r->meta_sreg.set = false; +} + +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg); + + if (r) + nft_xt_reg_clear(r); + + return r; +} + struct nft_family_ops { int (*add)(struct nft_handle *h, struct nftnl_rule *r, struct iptables_command_state *cs); @@ -84,9 +138,13 @@ struct nft_family_ops { const struct iptables_command_state *cs_b); void (*print_payload)(struct nftnl_expr *e, struct nftnl_expr_iter *iter); - void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + void (*parse_meta)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, struct iptables_command_state *cs); - void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + void (*parse_payload)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, struct iptables_command_state *cs); void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); void (*set_goto_flag)(struct iptables_command_state *cs); -- cgit v1.2.3 From f1a02b3aba5f57e7359f15d7f4250ac3835ebf61 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 23 Sep 2022 14:17:25 +0200 Subject: tests: extend native delinearize script Feed nft-generated ruleset to iptables-nft. At this time, this will NOT pass. because dissector can handle meta l4proto tcp ip saddr 1.2.3.4 but not ip saddr 1.2.3.4 meta l4proto tcp In the latter case, iptables-nft picks up the immediate value (6) as the ip address, because the first one (1.2.3.4) gets moved as PAYLOAD_PREV due to missing 'removal' of the CTX_PAYLOAD flag. This is error prone, so lets rewrite the dissector to track each register separately and auto-clear state on writes. Signed-off-by: Florian Westphal Acked-by: Phil Sutter --- .../testcases/nft-only/0010-iptables-nft-save.txt | 26 ++++++++++++++ .../testcases/nft-only/0010-native-delinearize_0 | 21 ++--------- .../shell/testcases/nft-only/0010-nft-native.txt | 41 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt create mode 100644 iptables/tests/shell/testcases/nft-only/0010-nft-native.txt diff --git a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt new file mode 100644 index 00000000..73d7108c --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt @@ -0,0 +1,26 @@ +*filter +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 23 -j ACCEPT +-A INPUT -s 1.2.3.0/24 -d 0.0.0.0/32 -p udp -m udp --dport 67:69 -j DROP +-A INPUT -s 1.0.0.0/8 -d 0.0.0.0/32 -p tcp -m tcp --sport 1024:65535 --dport 443 --tcp-flags SYN,ACK SYN -j ACCEPT +-A INPUT -p tcp -m tcp --dport 443 ! --tcp-flags SYN NONE -m comment --comment "checks if SYN bit is set" +-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "same as iptables --syn" +-A INPUT -p tcp -m tcp --tcp-flags SYN SYN +-A INPUT -p tcp -m tcp ! --tcp-flags SYN,ACK SYN,ACK +-A INPUT -d 0.0.0.0/1 -m ttl --ttl-eq 1 -j DROP +-A INPUT -d 0.0.0.0/2 -m ttl --ttl-gt 2 -j ACCEPT +-A INPUT -d 0.0.0.0/3 -m ttl --ttl-lt 254 -j ACCEPT +-A INPUT -d 0.0.0.0/4 -m ttl ! --ttl-eq 255 -j DROP +-A INPUT -d 8.0.0.0/5 -p icmp -j ACCEPT +-A INPUT -d 8.0.0.0/6 -p icmp -j ACCEPT +-A INPUT -d 10.0.0.0/7 -p icmp -j ACCEPT +-A INPUT -m pkttype --pkt-type broadcast -j ACCEPT +-A INPUT -m pkttype ! --pkt-type unicast -j DROP +-A INPUT -p tcp +-A INPUT -d 0.0.0.0/1 -p udp +-A FORWARD -m limit --limit 10/day +-A FORWARD -p udp -m udp --dport 42 +-A FORWARD -i lo -o lo+ -j NFLOG --nflog-prefix "should use NFLOG" --nflog-group 1 --nflog-size 123 --nflog-threshold 42 +COMMIT diff --git a/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 index cca36fd8..7859e76c 100755 --- a/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 +++ b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 @@ -5,22 +5,5 @@ nft -v >/dev/null || exit 0 set -e -nft -f - < 2 accept + ip daddr 0.0.0.0/3 ip ttl < 254 accept + ip daddr 0.0.0.0/4 ip ttl != 255 drop + + ip daddr 8.0.0.0/5 icmp type 1 accept + ip daddr 8.0.0.0/6 icmp type 2 icmp code port-unreachable accept + ip daddr 10.0.0.0/7 icmp type echo-request accept + + meta pkttype broadcast accept + meta pkttype != host drop + + ip saddr 0.0.0.0/0 ip protocol tcp + ip daddr 0.0.0.0/1 ip protocol udp + } + + chain FORWARD { + type filter hook forward priority filter; + limit rate 10/day counter + udp dport 42 counter + + # FIXME: can't dissect plain syslog + # meta iif "lo" log prefix "just doing a log" level alert flags tcp sequence,options + + # iif, not iifname, and wildcard + meta iif "lo" oifname "lo*" log group 1 prefix "should use NFLOG" queue-threshold 42 snaplen 123 + } +} -- cgit v1.2.3 From e8fce1d700d068f7cebf009ee02b85623be2d4c4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Sep 2022 18:53:50 +0200 Subject: ebtables: Drop unused OPT_* defines Obviously copied from legacy ebtables, not needed by ebtables-nft. OPT_CNT_* ones seem not even used in legacy anymore. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index b986fd9e..3887ea1a 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -168,10 +168,7 @@ int ebt_get_current_chain(const char *chain) #define OPT_ZERO 0x100 #define OPT_LOGICALIN 0x200 #define OPT_LOGICALOUT 0x400 -#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */ #define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */ -#define OPT_CNT_INCR 0x2000 /* This value is also defined in libebtc.c */ -#define OPT_CNT_DECR 0x4000 /* This value is also defined in libebtc.c */ /* Default command line options. Do not mess around with the already * assigned numbers unless you know what you are doing */ -- cgit v1.2.3 From 39cc849ed0f7ae0e5e09e3a2c278708fd36c8c14 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Sep 2022 19:03:47 +0200 Subject: ebtables: Eliminate OPT_TABLE The flag is used for duplicate option checking only and there is a boolean indicating the same already. So copy the error message from EBT_CHECK_OPTION() in situ and just take care not to disturb restore mode handling. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 3887ea1a..9aab3597 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -158,7 +158,6 @@ int ebt_get_current_chain(const char *chain) #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO) #define OPT_COMMAND 0x01 -#define OPT_TABLE 0x02 #define OPT_IN 0x04 #define OPT_OUT 0x08 #define OPT_JUMP 0x10 @@ -894,11 +893,13 @@ print_zero: } break; case 't': /* Table */ - ebt_check_option2(&flags, OPT_TABLE); if (restore && table_set) xtables_error(PARAMETER_PROBLEM, "The -t option cannot be used in %s.\n", xt_params->program_name); + else if (table_set) + xtables_error(PARAMETER_PROBLEM, + "Multiple use of same option not allowed"); if (!nft_table_builtin_find(h, optarg)) xtables_error(VERSION_PROBLEM, "table '%s' does not exist", -- cgit v1.2.3 From db420e268735e8499ca16146234ace79a9f1128a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Sep 2022 19:46:47 +0200 Subject: ebtables: Merge OPT_* flags with xshared ones Despite also including xshared.h, xtables-eb.c defined its own OPT_* flags with clashing values. Albeit ugly, this wasn't a problem in practice until commit 51d9d9e081344 ("ebtables: Support verbose mode") which introduced use of OPT_VERBOSE from xshared - with same value as the local OPT_PROTOCOL define. Eliminate the clash by appending ebtables-specific flags to the xshared enum and adjust for the different names of some others. Fixes: 51d9d9e081344 ("ebtables: Support verbose mode") Signed-off-by: Phil Sutter --- iptables/xshared.h | 5 +++++ iptables/xtables-eb.c | 20 ++++---------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/iptables/xshared.h b/iptables/xshared.h index 1a019a7c..f43c28f5 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -37,6 +37,11 @@ enum { OPT_OPCODE = 1 << 15, OPT_H_TYPE = 1 << 16, OPT_P_TYPE = 1 << 17, + /* below are for ebtables only */ + OPT_LOGICALIN = 1 << 18, + OPT_LOGICALOUT = 1 << 19, + OPT_COMMAND = 1 << 20, + OPT_ZERO = 1 << 21, }; enum { diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 9aab3597..631a3ceb 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -157,18 +157,6 @@ int ebt_get_current_chain(const char *chain) /* Checks whether a command has already been specified */ #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO) -#define OPT_COMMAND 0x01 -#define OPT_IN 0x04 -#define OPT_OUT 0x08 -#define OPT_JUMP 0x10 -#define OPT_PROTOCOL 0x20 -#define OPT_SOURCE 0x40 -#define OPT_DEST 0x80 -#define OPT_ZERO 0x100 -#define OPT_LOGICALIN 0x200 -#define OPT_LOGICALOUT 0x400 -#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */ - /* Default command line options. Do not mess around with the already * assigned numbers unless you know what you are doing */ struct option ebt_original_options[] = @@ -923,7 +911,7 @@ print_zero: xtables_error(PARAMETER_PROBLEM, "Command and option do not match"); if (c == 'i') { - ebt_check_option2(&flags, OPT_IN); + ebt_check_option2(&flags, OPT_VIANAMEIN); if (selected_chain > 2 && selected_chain < NF_BR_BROUTING) xtables_error(PARAMETER_PROBLEM, "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); @@ -943,7 +931,7 @@ print_zero: ebtables_parse_interface(optarg, cs.eb.logical_in); break; } else if (c == 'o') { - ebt_check_option2(&flags, OPT_OUT); + ebt_check_option2(&flags, OPT_VIANAMEOUT); if (selected_chain < 2 || selected_chain == NF_BR_BROUTING) xtables_error(PARAMETER_PROBLEM, "Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); @@ -980,7 +968,7 @@ print_zero: cs.eb.bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { - ebt_check_option2(&flags, OPT_DEST); + ebt_check_option2(&flags, OPT_DESTINATION); if (ebt_check_inverse2(optarg, argc, argv)) cs.eb.invflags |= EBT_IDEST; @@ -991,7 +979,7 @@ print_zero: cs.eb.bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { - ebt_check_option2(&flags, OPT_COUNT); + ebt_check_option2(&flags, OPT_COUNTERS); if (ebt_check_inverse2(optarg, argc, argv)) xtables_error(PARAMETER_PROBLEM, "Unexpected '!' after -c"); -- cgit v1.2.3 From 8dc22798bf813ce92aaac58a6fe8749fe3fc18dc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Sep 2022 23:15:37 +0200 Subject: nft-shared: Introduce __get_cmp_data() This is an inner function to get_cmp_data() returning the op value as-is for caller examination. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 17 ++++++++++------- iptables/nft-shared.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 555f74f0..f8de2b71 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -471,17 +471,20 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->h->ops->parse_match(match, ctx->cs); } -void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) +void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op) { uint32_t len; - uint8_t op; memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - if (op == NFT_CMP_NEQ) - *inv = true; - else - *inv = false; + *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); +} + +void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) +{ + uint8_t op; + + __get_cmp_data(e, data, dlen, &op); + *inv = (op == NFT_CMP_NEQ); } static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 42170638..8fcedcdd 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -217,6 +217,7 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags); +void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); void nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, -- cgit v1.2.3 From aa0b8b03f7c7e741ccd96360bd64d90ea8c3c3aa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 27 Sep 2022 23:19:34 +0200 Subject: ebtables: Support '-p Length' To match on Ethernet frames using the etherproto field as length value, ebtables accepts the special protocol name "LENGTH". Implement this in ebtables-nft using a native match for 'ether type < 0x0600'. Since extension 802_3 matches are valid only with such Ethernet frames, add a local add_match() wrapper which complains if the extension is used without '-p Length' parameter. Legacy ebtables does this within the extension's final_check callback, but it's not possible here due for lack of fw->bitmask field access. While being at it, add xlate support, adjust tests and make ebtables-nft print the case-insensitive argument with capital 'L' like legacy ebtables does. Signed-off-by: Phil Sutter --- extensions/generic.txlate | 6 +++ extensions/libebt_802_3.t | 6 ++- iptables/nft-bridge.c | 46 +++++++++++++++++----- .../ebtables/0002-ebtables-save-restore_0 | 12 +++--- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/extensions/generic.txlate b/extensions/generic.txlate index 9ae9a5b5..6779d6f8 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -67,6 +67,12 @@ nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oi ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00 nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter +ebtables-translate -I INPUT -p Length +nft insert rule bridge filter INPUT ether type < 0x0600 counter + +ebtables-translate -I INPUT -p ! Length +nft insert rule bridge filter INPUT ether type >= 0x0600 counter + # asterisk is not special in iptables and it is even a valid interface name iptables-translate -A FORWARD -i '*' -o 'eth*foo' nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t index ddfb2f0a..a138f35d 100644 --- a/extensions/libebt_802_3.t +++ b/extensions/libebt_802_3.t @@ -1,3 +1,5 @@ :INPUT,FORWARD,OUTPUT ---802_3-sap ! 0x0a -j CONTINUE;=;OK ---802_3-type 0x000a -j RETURN;=;OK +--802_3-sap ! 0x0a -j CONTINUE;=;FAIL +--802_3-type 0x000a -j RETURN;=;FAIL +-p Length --802_3-sap ! 0x0a -j CONTINUE;=;OK +-p Length --802_3-type 0x000a -j RETURN;=;OK diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 1121e864..659c5b58 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -100,6 +100,18 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) return add_action(r, cs, false); } +static int +nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, + struct nftnl_rule *r, struct xt_entry_match *m) +{ + if (!strcmp(m->u.user.name, "802_3") && + !(fw->bitmask & EBT_802_3)) + xtables_error(PARAMETER_PROBLEM, + "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH"); + + return add_match(h, r, m); +} + static int nft_bridge_add(struct nft_handle *h, struct nftnl_rule *r, struct iptables_command_state *cs) @@ -143,19 +155,26 @@ static int nft_bridge_add(struct nft_handle *h, } if ((fw->bitmask & EBT_NOPROTO) == 0) { + uint16_t ethproto = fw->ethproto; uint8_t reg; op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); add_payload(h, r, offsetof(struct ethhdr, h_proto), 2, NFT_PAYLOAD_LL_HEADER, ®); - add_cmp_u16(r, fw->ethproto, op, reg); + + if (fw->bitmask & EBT_802_3) { + op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE); + ethproto = htons(0x0600); + } + + add_cmp_u16(r, ethproto, op, reg); } add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO); for (iter = cs->match_list; iter; iter = iter->next) { if (iter->ismatch) { - if (add_match(h, r, iter->u.match->m)) + if (nft_bridge_add_match(h, fw, r, iter->u.match->m)) break; } else { if (add_target(r, iter->u.watcher->t)) @@ -214,6 +233,7 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, struct ebt_entry *fw = &cs->eb; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; + uint8_t op; bool inv; int i; @@ -246,8 +266,14 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, fw->bitmask |= EBT_ISOURCE; break; case offsetof(struct ethhdr, h_proto): - get_cmp_data(e, ðproto, sizeof(ethproto), &inv); - fw->ethproto = ethproto; + __get_cmp_data(e, ðproto, sizeof(ethproto), &op); + if (ethproto == htons(0x0600)) { + fw->bitmask |= EBT_802_3; + inv = (op == NFT_CMP_GTE); + } else { + fw->ethproto = ethproto; + inv = (op == NFT_CMP_NEQ); + } if (inv) fw->invflags |= EBT_IPROTO; fw->bitmask &= ~EBT_NOPROTO; @@ -613,7 +639,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("! "); if (bitmask & EBT_802_3) { - printf("length "); + printf("Length "); return; } @@ -627,7 +653,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) static void __nft_bridge_save_rule(const struct iptables_command_state *cs, unsigned int format) { - if (cs->eb.ethproto) + if (!(cs->eb.bitmask & EBT_NOPROTO)) print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO, cs->eb.bitmask); if (cs->eb.bitmask & EBT_ISOURCE) @@ -866,7 +892,10 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, xlate_ifname(xl, "meta obrname", cs->eb.logical_out, cs->eb.invflags & EBT_ILOGICALOUT); - if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { + if (cs->eb.bitmask & EBT_802_3) { + xt_xlate_add(xl, "ether type %s 0x0600 ", + cs->eb.invflags & EBT_IPROTO ? ">=" : "<"); + } else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { const char *implicit = NULL; switch (ntohs(cs->eb.ethproto)) { @@ -889,9 +918,6 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, ntohs(cs->eb.ethproto)); } - if (cs->eb.bitmask & EBT_802_3) - return 0; - if (cs->eb.bitmask & EBT_ISOURCE) nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE, cs->eb.sourcemac, cs->eb.sourcemsk); 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 ccdef19c..0537f567 100755 --- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 +++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 @@ -13,8 +13,8 @@ $XT_MULTI ebtables -A INPUT -p IPv4 -i lo -j ACCEPT $XT_MULTI ebtables -P FORWARD DROP $XT_MULTI ebtables -A OUTPUT -s ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff -j DROP $XT_MULTI ebtables -N foo -$XT_MULTI ebtables -A foo --802_3-sap 0x23 -j ACCEPT -$XT_MULTI ebtables -A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT #$XT_MULTI ebtables -A foo --among-dst fe:ed:ba:be:00:01,fe:ed:ba:be:00:02,fe:ed:ba:be:00:03 -j ACCEPT $XT_MULTI ebtables -A foo -p ARP --arp-gratuitous -j ACCEPT $XT_MULTI ebtables -A foo -p ARP --arp-opcode Request -j ACCEPT @@ -44,7 +44,7 @@ $XT_MULTI ebtables -A foo --pkttype-type multicast -j ACCEPT $XT_MULTI ebtables -A foo --stp-type config -j ACCEPT #$XT_MULTI ebtables -A foo --vlan-id 42 -j ACCEPT -$XT_MULTI ebtables -A foo --802_3-sap 0x23 --limit 100 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 --limit 100 -j ACCEPT $XT_MULTI ebtables -A foo --pkttype-type multicast --log $XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT @@ -75,8 +75,8 @@ DUMP='*filter -A INPUT -p IPv4 -i lo -j ACCEPT -A FORWARD -j foo -A OUTPUT -s Broadcast -j DROP --A foo --802_3-sap 0x23 -j ACCEPT --A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT +-A foo -p Length --802_3-sap 0x23 -j ACCEPT +-A foo -p Length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT -A foo -p ARP --arp-gratuitous -j ACCEPT -A foo -p ARP --arp-op Request -j ACCEPT -A foo -p ARP --arp-ip-src 10.0.0.1 -j ACCEPT @@ -96,7 +96,7 @@ DUMP='*filter -A foo --nflog-group 1 -j CONTINUE -A foo --pkttype-type multicast -j ACCEPT -A foo --stp-type config -j ACCEPT --A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT +-A foo -p Length --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT -A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE -A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT *nat -- cgit v1.2.3 From eddbb27651b93ac6f329bf8113223e7360ea7613 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 4 Aug 2022 17:01:26 +0200 Subject: ebtables: Fix among match Fixed commit broke among match in two ways: 1) The two lookup sizes are 12 and 6, not 12 and 4 - among supports either ether+IP or ether only, not IP only. 2) Adding two to sreg_count to get the second register is too simple: It works only for four byte regs, not the 16 byte ones. The first register is always a 16 byte one, though. Fixing (1) is trivial, fix (2) by introduction of nft_get_next_reg() doing the right thing. For consistency, use it for among match creation, too. Fixes: f315af1cf8871 ("nft: track each register individually") Signed-off-by: Phil Sutter --- iptables/nft-bridge.c | 4 ++-- iptables/nft-shared.c | 16 ++++++++++++++++ iptables/nft-shared.h | 5 +++++ iptables/nft.c | 6 ++---- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 659c5b58..596dfdf8 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -349,7 +349,7 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } - sreg_count += 2; + sreg_count = nft_get_next_reg(sreg_count, ETH_ALEN); reg = nft_xt_ctx_get_sreg(ctx, sreg_count); if (!reg) { @@ -375,7 +375,7 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } break; - case 4: /* ipv4addr */ + case 6: /* ether */ val = lookup_check_ether_payload(reg->payload.base, reg->payload.offset, reg->payload.len); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index f8de2b71..909fe648 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -10,6 +10,7 @@ * This code has been sponsored by Sophos Astaro */ +#include #include #include #include @@ -1603,3 +1604,18 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, return 0; } + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size) +{ + /* convert size to NETLINK_ALIGN-sized chunks */ + size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN; + + /* map 16byte reg to 4byte one */ + if (reg < __NFT_REG_MAX) + reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE; + + reg += size; + assert(reg <= NFT_REG32_15); + + return reg; +} diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 8fcedcdd..c07d3270 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -276,4 +276,9 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_c #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) +/* simplified nftables:include/netlink.h, netlink_padded_len() */ +#define NETLINK_ALIGN 4 + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size); + #endif diff --git a/iptables/nft.c b/iptables/nft.c index 2165733f..09cb19c9 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1133,9 +1133,6 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags) return e; } -/* simplified nftables:include/netlink.h, netlink_padded_len() */ -#define NETLINK_ALIGN 4 - /* from nftables:include/datatype.h, TYPE_BITS */ #define CONCAT_TYPE_BITS 6 @@ -1208,8 +1205,9 @@ static int __add_nft_among(struct nft_handle *h, const char *table, nftnl_rule_add_expr(r, e); if (ip) { + reg = nft_get_next_reg(reg, ETH_ALEN); e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], - sizeof(struct in_addr), NFT_REG32_02); + sizeof(struct in_addr), reg); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); -- cgit v1.2.3 From 66806feef085c0504966c484f687bdf7b09510e3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 28 Sep 2022 18:08:43 +0200 Subject: nft: Fix meta statement parsing The function nft_meta_set_to_target() would always bail since nothing sets 'sreg->meta_sreg.set' to true. This is obvious, as the immediate expression "filling" the source register does not indicate its purpose. The whole source register purpose storing in meta_sreg seems to be pointless, so drop it altogether. Fixes: f315af1cf8871 ("nft: track each register individually") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 14 +++++++++----- iptables/nft-shared.h | 6 ------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 909fe648..996cff99 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -503,10 +503,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, if (!sreg) return; - if (sreg->meta_sreg.set == 0) - return; - - switch (sreg->meta_sreg.key) { + switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) { case NFT_META_NFTRACE: if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { ctx->errmsg = "meta nftrace but reg not immediate"; @@ -526,8 +523,10 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, } target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) + if (target == NULL) { + ctx->errmsg = "target TRACE not found"; return; + } size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; @@ -1303,6 +1302,11 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, else if (strcmp(name, "range") == 0) nft_parse_range(&ctx, expr); + if (ctx.errmsg) { + fprintf(stderr, "%s", ctx.errmsg); + ctx.errmsg = NULL; + } + expr = nftnl_expr_iter_next(iter); } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index c07d3270..3d935d53 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -68,11 +68,6 @@ struct nft_xt_ctx_reg { uint32_t xor[4]; bool set; } bitwise; - - struct { - uint32_t key; - bool set; - } meta_sreg; }; struct nft_xt_ctx { @@ -118,7 +113,6 @@ static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) { r->type = 0; r->bitwise.set = false; - r->meta_sreg.set = false; } static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) -- cgit v1.2.3 From 6ffd3674af160b7e59b480d13a12bf82bea32f04 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 28 Sep 2022 18:42:02 +0200 Subject: nft-bridge: Drop 'sreg_count' variable It is not needed, one can just use 'reg' function parameter in its place. Signed-off-by: Phil Sutter Acked-by: Florian Westphal --- iptables/nft-bridge.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 596dfdf8..d1385cc3 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -324,7 +324,6 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, bool *dst, bool *ip) { const struct nft_xt_ctx_reg *reg; - uint32_t sreg_count; int val, val2 = -1; reg = nft_xt_ctx_get_sreg(ctx, sreg); @@ -336,7 +335,6 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } - sreg_count = sreg; switch (key_len) { case 12: /* ether + ipv4addr */ val = lookup_check_ether_payload(reg->payload.base, @@ -349,9 +347,9 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } - sreg_count = nft_get_next_reg(sreg_count, ETH_ALEN); + sreg = nft_get_next_reg(sreg, ETH_ALEN); - reg = nft_xt_ctx_get_sreg(ctx, sreg_count); + reg = nft_xt_ctx_get_sreg(ctx, sreg); if (!reg) { ctx->errmsg = "next lookup register is invalid"; return -1; -- cgit v1.2.3 From 1cd5e6b44129e46b439b23d84672c6f32ce82091 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Sep 2022 14:46:26 +0200 Subject: tests: iptables-test: Simplify '-N' option a bit Instead of hard-coding, store the netns name in args.netns if the flag was given. The value defaults to None, so existing 'if netns' checks are still valid. Signed-off-by: Phil Sutter --- iptables-test.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 6acaa822..69c96b79 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -79,12 +79,13 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): :param res: expected result of the rule. Valid values: "OK", "FAIL" :param filename: name of the file tested (used for print_error purposes) :param lineno: line number being tested (used for print_error purposes) + :param netns: network namespace to call commands in (or None) ''' ret = 0 cmd = iptables + " -A " + rule if netns: - cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + cmd + cmd = "ip netns exec " + netns + " " + EXECUTABLE + " " + cmd ret = execute_cmd(cmd, filename, lineno) @@ -126,7 +127,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): command = EXECUTABLE + " " + command if netns: - command = "ip netns exec ____iptables-container-test " + command + command = "ip netns exec " + netns + " " + command args = tokens[1:] proc = subprocess.Popen(command, shell=True, @@ -226,6 +227,7 @@ def run_test_file(filename, netns): Runs a test file :param filename: name of the file with the test rules + :param netns: network namespace to perform test run in ''' # # if this is not a test file, skip. @@ -262,7 +264,7 @@ def run_test_file(filename, netns): total_test_passed = True if netns: - execute_cmd("ip netns add ____iptables-container-test", filename, 0) + execute_cmd("ip netns add " + netns, filename, 0) for lineno, line in enumerate(f): if line[0] == "#" or len(line.strip()) == 0: @@ -276,7 +278,7 @@ def run_test_file(filename, netns): if line[0] == "@": external_cmd = line.rstrip()[1:] if netns: - external_cmd = "ip netns exec ____iptables-container-test " + external_cmd + external_cmd = "ip netns exec " + netns + " " + external_cmd execute_cmd(external_cmd, filename, lineno) continue @@ -284,7 +286,7 @@ def run_test_file(filename, netns): if line[0] == "%": external_cmd = line.rstrip()[1:] if netns: - external_cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + external_cmd + external_cmd = "ip netns exec " + netns + " " + EXECUTABLE + " " + external_cmd execute_cmd(external_cmd, filename, lineno) continue @@ -334,7 +336,7 @@ def run_test_file(filename, netns): passed += 1 if netns: - execute_cmd("ip netns del ____iptables-container-test", filename, 0) + execute_cmd("ip netns del " + netns, filename, 0) if total_test_passed: print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) @@ -400,7 +402,8 @@ def main(): help='Check for missing tests') parser.add_argument('-n', '--nftables', action='store_true', help='Test iptables-over-nftables') - parser.add_argument('-N', '--netns', action='store_true', + parser.add_argument('-N', '--netns', action='store_const', + const='____iptables-container-test', help='Test netnamespace path') parser.add_argument('--no-netns', action='store_true', help='Do not run testsuite in own network namespace') -- cgit v1.2.3 From f6c7affd8713ff92d6bfecadd31b6b75a8a9e172 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Sep 2022 14:48:29 +0200 Subject: tests: iptables-test: Simplify execute_cmd() calling Default 'lineno' parameter to zero, Signed-off-by: Phil Sutter --- iptables-test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 69c96b79..25561bc9 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -168,7 +168,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): return delete_rule(iptables, rule, filename, lineno) -def execute_cmd(cmd, filename, lineno): +def execute_cmd(cmd, filename, lineno = 0): ''' Executes a command, checking for segfaults and returning the command exit code. @@ -264,7 +264,7 @@ def run_test_file(filename, netns): total_test_passed = True if netns: - execute_cmd("ip netns add " + netns, filename, 0) + execute_cmd("ip netns add " + netns, filename) for lineno, line in enumerate(f): if line[0] == "#" or len(line.strip()) == 0: @@ -336,7 +336,7 @@ def run_test_file(filename, netns): passed += 1 if netns: - execute_cmd("ip netns del " + netns, filename, 0) + execute_cmd("ip netns del " + netns, filename) if total_test_passed: print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) -- cgit v1.2.3 From 33e35c1a32f5a1b131cb57ad28461ddc9889c0af Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Sep 2022 15:52:40 +0200 Subject: tests: iptables-test: Pass netns to execute_cmd() The command to run might have to be prefixed. Once if the command is 'iptables' (or related) to define the variant, once if '-N' was given to run the command inside the netns. Doing both prefixing inside execute_cmd() avoids a potential conflict and thus simplifies things: The "external command" and "external iptables call" lines become identical in handling, there is no need for a separate prefix char anymore. As a side-effect, this commit also fixes for delete_rule() calls in error case ignoring the netns value. Signed-off-by: Phil Sutter --- iptables-test.py | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 25561bc9..6504b231 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -54,12 +54,12 @@ def print_error(reason, filename=None, lineno=None): ": line %d (%s)" % (lineno, reason), file=sys.stderr) -def delete_rule(iptables, rule, filename, lineno): +def delete_rule(iptables, rule, filename, lineno, netns = None): ''' Removes an iptables rule ''' cmd = iptables + " -D " + rule - ret = execute_cmd(cmd, filename, lineno) + ret = execute_cmd(cmd, filename, lineno, netns) if ret == 1: reason = "cannot delete: " + iptables + " -I " + rule print_error(reason, filename, lineno) @@ -84,10 +84,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): ret = 0 cmd = iptables + " -A " + rule - if netns: - cmd = "ip netns exec " + netns + " " + EXECUTABLE + " " + cmd - - ret = execute_cmd(cmd, filename, lineno) + ret = execute_cmd(cmd, filename, lineno, netns) # # report failed test @@ -104,7 +101,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res == "FAIL": reason = "should fail: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 matching = 0 @@ -141,7 +138,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if proc.returncode == -11: reason = "iptables-save segfaults: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 # find the rule @@ -150,7 +147,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res == "OK": reason = "cannot find: " + iptables + " -I " + rule print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 else: # do not report this error @@ -159,7 +156,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res != "OK": reason = "should not match: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 # Test "ip netns del NETNS" path with rules in place @@ -168,7 +165,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): return delete_rule(iptables, rule, filename, lineno) -def execute_cmd(cmd, filename, lineno = 0): +def execute_cmd(cmd, filename, lineno = 0, netns = None): ''' Executes a command, checking for segfaults and returning the command exit code. @@ -176,11 +173,15 @@ def execute_cmd(cmd, filename, lineno = 0): :param cmd: string with the command to be executed :param filename: name of the file tested (used for print_error purposes) :param lineno: line number being tested (used for print_error purposes) + :param netns: network namespace to run command in ''' global log_file if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '): cmd = EXECUTABLE + " " + cmd + if netns: + cmd = "ip netns exec " + netns + " " + cmd + print("command: {}".format(cmd), file=log_file) ret = subprocess.call(cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT, stdout=log_file) @@ -274,20 +275,11 @@ def run_test_file(filename, netns): chain_array = line.rstrip()[1:].split(",") continue - # external non-iptables invocation, executed as is. - if line[0] == "@": - external_cmd = line.rstrip()[1:] - if netns: - external_cmd = "ip netns exec " + netns + " " + external_cmd - execute_cmd(external_cmd, filename, lineno) - continue - - # external iptables invocation, executed as is. - if line[0] == "%": + # external command invocation, executed as is. + # detects iptables commands to prefix with EXECUTABLE automatically + if line[0] in ["@", "%"]: external_cmd = line.rstrip()[1:] - if netns: - external_cmd = "ip netns exec " + netns + " " + EXECUTABLE + " " + external_cmd - execute_cmd(external_cmd, filename, lineno) + execute_cmd(external_cmd, filename, lineno, netns) continue if line[0] == "*": -- cgit v1.2.3 From d0e283469985515146bd158ab374307684f5f363 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Sep 2022 16:00:09 +0200 Subject: tests: iptables-test: Test both variants by default Via '--legacy' and '--nftables' flags one may choose the variant to test. Change the default (none of them given) from legacy to both, by effectively running twice. Prefix the summary line with the tested variant for clarity and print a total count line as well. Signed-off-by: Phil Sutter --- iptables-test.py | 84 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index 6504b231..b5a70e44 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -408,10 +408,13 @@ def main(): show_missing() return - global EXECUTABLE - EXECUTABLE = "xtables-legacy-multi" + variants = [] + if args.legacy: + variants.append("legacy") if args.nftables: - EXECUTABLE = "xtables-nft-multi" + variants.append("nft") + if len(variants) == 0: + variants = [ "legacy", "nft" ] if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) @@ -426,36 +429,51 @@ def main(): os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), os.getenv("PATH"))) - test_files = 0 - tests = 0 - passed = 0 - - # setup global var log file - global log_file - try: - log_file = open(LOGFILE, 'w') - except IOError: - print("Couldn't open log file %s" % LOGFILE, file=sys.stderr) - return - - if args.filename: - file_list = args.filename - else: - file_list = [os.path.join(EXTENSIONS_PATH, i) - for i in os.listdir(EXTENSIONS_PATH) - if i.endswith('.t')] - file_list.sort() - - for filename in file_list: - file_tests, file_passed = run_test_file(filename, args.netns) - if file_tests: - tests += file_tests - passed += file_passed - test_files += 1 - - print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed)) - return passed - tests - + total_test_files = 0 + total_passed = 0 + total_tests = 0 + for variant in variants: + global EXECUTABLE + EXECUTABLE = "xtables-" + variant + "-multi" + + test_files = 0 + tests = 0 + passed = 0 + + # setup global var log file + global log_file + try: + log_file = open(LOGFILE, 'w') + except IOError: + print("Couldn't open log file %s" % LOGFILE, file=sys.stderr) + return + + if args.filename: + file_list = args.filename + else: + file_list = [os.path.join(EXTENSIONS_PATH, i) + for i in os.listdir(EXTENSIONS_PATH) + if i.endswith('.t')] + file_list.sort() + + for filename in file_list: + file_tests, file_passed = run_test_file(filename, args.netns) + if file_tests: + tests += file_tests + passed += file_passed + test_files += 1 + + print("%s: %d test files, %d unit tests, %d passed" + % (variant, test_files, tests, passed)) + + total_passed += passed + total_tests += tests + total_test_files = max(total_test_files, test_files) + + if len(variants) > 1: + print("total: %d test files, %d unit tests, %d passed" + % (total_test_files, total_tests, total_passed)) + return total_passed - total_tests if __name__ == '__main__': sys.exit(main()) -- cgit v1.2.3 From eafe731a50058ed59305ee4ab1ea2d63d6c4e86e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 29 Sep 2022 19:11:55 +0200 Subject: extensions: among: Remove pointless fall through This seems to be a leftover from an earlier version of the switch(). This fall through is never effective as the next case's code will never apply. So just break instead. Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support") Signed-off-by: Phil Sutter --- extensions/libebt_among.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c index 7eb898f9..c607a775 100644 --- a/extensions/libebt_among.c +++ b/extensions/libebt_among.c @@ -152,10 +152,9 @@ static int bramong_parse(int c, char **argv, int invert, xtables_error(PARAMETER_PROBLEM, "File should only contain one line"); optarg[flen-1] = '\0'; - /* fall through */ + break; case AMONG_DST: - if (c == AMONG_DST) - dst = true; + dst = true; /* fall through */ case AMONG_SRC: break; -- cgit v1.2.3 From fca04aa7a53252464c289997e71de10189971da6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 30 Sep 2022 17:51:55 +0200 Subject: extensions: among: Fix for use with ebtables-restore When restoring multiple rules which use among match, new size may be smaller than the old one which caused invalid writes by the memcpy() call. Expect this and realloc the match only if it needs to grow. Also use realloc instead of freeing and allocating from scratch. Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support") Signed-off-by: Phil Sutter --- extensions/libebt_among.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c index c607a775..1eab2019 100644 --- a/extensions/libebt_among.c +++ b/extensions/libebt_among.c @@ -119,7 +119,6 @@ static int bramong_parse(int c, char **argv, int invert, struct xt_entry_match **match) { struct nft_among_data *data = (struct nft_among_data *)(*match)->data; - struct xt_entry_match *new_match; bool have_ip, dst = false; size_t new_size, cnt; struct stat stats; @@ -170,18 +169,17 @@ static int bramong_parse(int c, char **argv, int invert, new_size *= sizeof(struct nft_among_pair); new_size += XT_ALIGN(sizeof(struct xt_entry_match)) + sizeof(struct nft_among_data); - new_match = xtables_calloc(1, new_size); - memcpy(new_match, *match, (*match)->u.match_size); - new_match->u.match_size = new_size; - data = (struct nft_among_data *)new_match->data; + if (new_size > (*match)->u.match_size) { + *match = xtables_realloc(*match, new_size); + (*match)->u.match_size = new_size; + data = (struct nft_among_data *)(*match)->data; + } + have_ip = nft_among_pairs_have_ip(optarg); poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip); parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip); - free(*match); - *match = new_match; - if (c == AMONG_DST_F || c == AMONG_SRC_F) { munmap(argv, flen); close(fd); -- cgit v1.2.3 From 262dff31a998ef8e2507bbfd9349d761769888da Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:15:35 +0200 Subject: extensions: libebt_stp: Eliminate duplicate space in output No need for print_range() to print a trailing whitespace, caller does this already. Fixes: fd8d7d7e5d911 ("ebtables-nft: add stp match") Signed-off-by: Phil Sutter --- extensions/libebt_stp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c index 3e9e2447..41059baa 100644 --- a/extensions/libebt_stp.c +++ b/extensions/libebt_stp.c @@ -146,9 +146,9 @@ out: static void print_range(unsigned int l, unsigned int u) { if (l == u) - printf("%u ", l); + printf("%u", l); else - printf("%u:%u ", l, u); + printf("%u:%u", l, u); } static int -- cgit v1.2.3 From 11e06cbb3a87739a3d958ba4c2f08fea7b100a68 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:17:50 +0200 Subject: extensions: libip6t_dst: Fix output for empty options If no --dst-opts were given, print_options() would print just a whitespace. Fixes: 73866357e4a7a ("iptables: do not print trailing whitespaces") Signed-off-by: Phil Sutter --- extensions/libip6t_dst.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c index bf0e3e43..baa010f5 100644 --- a/extensions/libip6t_dst.c +++ b/extensions/libip6t_dst.c @@ -125,15 +125,15 @@ static void print_options(unsigned int optsnr, uint16_t *optsp) { unsigned int i; + char sep = ' '; - printf(" "); for(i = 0; i < optsnr; i++) { - printf("%d", (optsp[i] & 0xFF00) >> 8); + printf("%c%d", sep, (optsp[i] & 0xFF00) >> 8); if ((optsp[i] & 0x00FF) != 0x00FF) printf(":%d", (optsp[i] & 0x00FF)); - printf("%c", (i != optsnr - 1) ? ',' : ' '); + sep = ','; } } -- cgit v1.2.3 From dba32a76aacf84181a9bd3ba1e301e59ab49d370 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:36:50 +0200 Subject: extensions: TCPOPTSTRIP: Do not print empty options No point in printing anything if none of the bits are set. Fixes: aef4c1e727563 ("libxt_TCPOPTSTRIP") Signed-off-by: Phil Sutter --- extensions/libxt_TCPOPTSTRIP.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c index 6ea34892..ff873f98 100644 --- a/extensions/libxt_TCPOPTSTRIP.c +++ b/extensions/libxt_TCPOPTSTRIP.c @@ -142,6 +142,13 @@ tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info, } } +static bool tcpoptstrip_empty(const struct xt_tcpoptstrip_target_info *info) +{ + static const struct xt_tcpoptstrip_target_info empty = {}; + + return memcmp(info, &empty, sizeof(empty)) == 0; +} + static void tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target, int numeric) @@ -149,6 +156,9 @@ tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; + if (tcpoptstrip_empty(info)) + return; + printf(" TCPOPTSTRIP options "); tcpoptstrip_print_list(info, numeric); } @@ -159,6 +169,9 @@ tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target) const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; + if (tcpoptstrip_empty(info)) + return; + printf(" --strip-options "); tcpoptstrip_print_list(info, true); } -- cgit v1.2.3 From 9cdb52d655608e92f101cb56562e4756a47abd81 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:10:34 +0200 Subject: extensions: libebt_log: Avoid empty log-prefix in output Just like iptables LOG target, omit --log-prefix from output if the string is empty. --- extensions/libebt_log.c | 7 ++++--- extensions/libebt_log.t | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 8858cf0e..47708d79 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -161,9 +161,10 @@ static void brlog_print(const void *ip, const struct xt_entry_target *target, { struct ebt_log_info *loginfo = (struct ebt_log_info *)target->data; - printf("--log-level %s --log-prefix \"%s\"", - eight_priority[loginfo->loglevel].c_name, - loginfo->prefix); + printf("--log-level %s", eight_priority[loginfo->loglevel].c_name); + + if (loginfo->prefix[0]) + printf(" --log-prefix \"%s\"", loginfo->prefix); if (loginfo->bitmask & EBT_LOG_IP) printf(" --log-ip"); diff --git a/extensions/libebt_log.t b/extensions/libebt_log.t index a0df6169..f7116c41 100644 --- a/extensions/libebt_log.t +++ b/extensions/libebt_log.t @@ -1,6 +1,6 @@ :INPUT,FORWARD,OUTPUT --log;=;OK --log-level crit;=;OK ---log-level 1;--log-level alert --log-prefix "";OK ---log-level emerg --log-ip --log-arp --log-ip6;--log-level emerg --log-prefix "" --log-ip --log-arp --log-ip6 -j CONTINUE;OK +--log-level 1;--log-level alert;OK +--log-level emerg --log-ip --log-arp --log-ip6;=;OK --log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo;--log-level crit --log-prefix "foo" --log-ip --log-arp --log-ip6 -j CONTINUE;OK -- cgit v1.2.3 From de043bbf2b78cad83a639e27c75263aa478e8cc4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 30 Sep 2022 18:06:10 +0200 Subject: tests: IDLETIMER.t: Fix syntax, support for restore input Expected output was wrong in the last OK test, probably defeating rule search check. Also use a different label, otherwise the kernel will reject the second idletimer with same label but different type if both rules are added at once. Fixes: 85b9ec8615428 ("extensions: IDLETIMER: Add alarm timer option") --- extensions/libxt_IDLETIMER.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t index e8f306d2..3345d5be 100644 --- a/extensions/libxt_IDLETIMER.t +++ b/extensions/libxt_IDLETIMER.t @@ -2,4 +2,4 @@ -j IDLETIMER --timeout;;FAIL -j IDLETIMER --timeout 42;;FAIL -j IDLETIMER --timeout 42 --label foo;=;OK --j IDLETIMER --timeout 42 --label foo --alarm;;OK +-j IDLETIMER --timeout 42 --label bar --alarm;=;OK -- cgit v1.2.3 From dafb31980c4469fd28964b9703d3c77433cc7d21 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 5 Oct 2022 20:29:36 +0200 Subject: tests: libebt_stp.t: Drop duplicate whitespace Code was fixed but the testcase adjustment slipped through. Fixes: 262dff31a998e ("extensions: libebt_stp: Eliminate duplicate space in output") --- extensions/libebt_stp.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libebt_stp.t b/extensions/libebt_stp.t index 0c6b77b9..17d6c1c0 100644 --- a/extensions/libebt_stp.t +++ b/extensions/libebt_stp.t @@ -1,7 +1,7 @@ :INPUT,FORWARD,OUTPUT --stp-type 1;=;OK --stp-flags 0x1;--stp-flags topology-change -j CONTINUE;OK ---stp-root-prio 1 -j ACCEPT;=;OK +--stp-root-prio 1 -j ACCEPT;=;OK --stp-root-addr 0d:ea:d0:0b:ee:f0;=;OK --stp-root-cost 1;=;OK --stp-sender-prio 1;=;OK -- cgit v1.2.3 From d89cc773618ddbdedd1ae967a8e686adbaf501f6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 6 Oct 2022 02:08:10 +0200 Subject: tests: shell: Fix expected output for ip6tables dst match Forgot to update the shell testsuites when fixing for duplicate whitespace in output. Fixes: 11e06cbb3a877 ("extensions: libip6t_dst: Fix output for empty options") Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index 2a1518d6..cc18a94b 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -12,7 +12,7 @@ VOUT2='ACCEPT all opt -- in eth2 out eth3 feed:babe::4 -> feed:babe::5' RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route' VOUT3=' ipv6-icmp opt -- in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' RULE4='-m dst --dst-len 42 -m rt --rt-type 23' -VOUT4=' all opt -- in * out * ::/0 -> ::/0 dst length:42 rt type:23' +VOUT4=' all opt -- in * out * ::/0 -> ::/0 dst length:42 rt type:23' RULE5='-m frag --fragid 1337 -j LOG' VOUT5='LOG all opt -- in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' @@ -36,7 +36,7 @@ Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::1 feed:babe::2 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::4 feed:babe::5 0 0 58 -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 - 0 0 0 -- * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 0 -- * * ::/0 ::/0 dst length:42 rt type:23 0 0 LOG 0 -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) -- cgit v1.2.3 From 28c7bf020e9b1dcf94bd3162ce9c354c06bb6f97 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 6 Oct 2022 02:10:44 +0200 Subject: tests: shell: Fix expected ebtables log target output Forgot to update shell testsuite when removing empty --log-prefix options. Fixes: 9cdb52d655608 ("extensions: libebt_log: Avoid empty log-prefix in output") Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 | 4 ++-- .../tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 0537f567..1091a4e8 100755 --- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 +++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 @@ -91,13 +91,13 @@ DUMP='*filter -A foo -p IPv6 --ip6-dst feed:babe::/64 -j ACCEPT -A foo -p IPv6 --ip6-proto tcp -j ACCEPT -A foo --limit 100/sec --limit-burst 42 -j ACCEPT --A foo --log-level notice --log-prefix "" -j CONTINUE +-A foo --log-level notice -j CONTINUE -A foo -j mark --mark-set 0x23 --mark-target ACCEPT -A foo --nflog-group 1 -j CONTINUE -A foo --pkttype-type multicast -j ACCEPT -A foo --stp-type config -j ACCEPT -A foo -p Length --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT --A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE +-A foo --pkttype-type multicast --log-level notice -j CONTINUE -A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT *nat :PREROUTING ACCEPT diff --git a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 index 63891c1b..7554ef85 100755 --- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 +++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 @@ -24,7 +24,7 @@ EXPECT='*filter -A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT -A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT -A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE --A FORWARD --log-level notice --log-prefix "" -j CONTINUE' +-A FORWARD --log-level notice -j CONTINUE' $XT_MULTI ebtables --init-table $XT_MULTI ebtables-restore <<<$DUMP -- cgit v1.2.3 From 97bf4e68fc0794adba3243fd96f40f4568e7216f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 7 Oct 2022 18:29:07 +0200 Subject: libiptc: Fix for segfault when renaming a chain This is an odd bug: If the number of chains is right and one renames the last one in the list, libiptc dereferences a NULL pointer. Add fix and test case for it. Fixes: 64ff47cde38e4 ("libiptc: fix chain rename bug in libiptc") Reported-by: Julien Castets Signed-off-by: Phil Sutter --- .../tests/shell/testcases/chain/0006rename-segfault_0 | 19 +++++++++++++++++++ libiptc/libiptc.c | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100755 iptables/tests/shell/testcases/chain/0006rename-segfault_0 diff --git a/iptables/tests/shell/testcases/chain/0006rename-segfault_0 b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 new file mode 100755 index 00000000..c10a8006 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Cover for a bug in libiptc: +# - the chain 'node-98-tmp' is the last in the list sorted by name +# - there are 81 chains in total, so three chain index buckets +# - the last index bucket contains only the 'node-98-tmp' chain +# => rename temporarily removes it from the bucket, leaving a NULL bucket +# behind which is dereferenced later when inserting the chain again with new +# name again + +( + echo "*filter" + for chain in node-1 node-10 node-101 node-102 node-104 node-107 node-11 node-12 node-13 node-14 node-15 node-16 node-17 node-18 node-19 node-2 node-20 node-21 node-22 node-23 node-25 node-26 node-27 node-28 node-29 node-3 node-30 node-31 node-32 node-33 node-34 node-36 node-37 node-39 node-4 node-40 node-41 node-42 node-43 node-44 node-45 node-46 node-47 node-48 node-49 node-5 node-50 node-51 node-53 node-54 node-55 node-56 node-57 node-58 node-59 node-6 node-60 node-61 node-62 node-63 node-64 node-65 node-66 node-68 node-69 node-7 node-70 node-71 node-74 node-75 node-76 node-8 node-80 node-81 node-86 node-89 node-9 node-92 node-93 node-95 node-98-tmp; do + echo ":$chain - [0:0]" + done + echo "COMMIT" +) | $XT_MULTI iptables-restore +$XT_MULTI iptables -E node-98-tmp node-98 +exit $? diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index ceeb017b..97823f93 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -606,6 +606,15 @@ static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handl if (index_ptr == &c->list) { /* Chain used as index ptr */ + /* If this is the last chain in the list, its index bucket just + * became empty. Adjust the size to avoid a NULL-pointer deref + * later. + */ + if (next == &h->chains) { + h->chain_index_sz--; + return 0; + } + /* See if its possible to avoid a rebuild, by shifting * to next pointer. Its possible if the next pointer * is located in the same index bucket. -- cgit v1.2.3 From 610ed9c8c733e3b40787e975cdcb957981b4a6c5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 7 Oct 2022 22:16:43 +0200 Subject: nft: Fix compile with -DDEBUG Conversion from 'ctx' to 'reg' missed some of the DEBUGP() calls. Fixes: f315af1cf8871 ("nft: track each register individually") Signed-off-by: Phil Sutter --- iptables/nft-bridge.c | 8 ++++---- iptables/nft-ipv6.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index d1385cc3..749cbc6f 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -365,8 +365,8 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, reg->payload.len); if (val2 < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } else if (val != val2) { DEBUGP("mismatching payload match offsets\n"); @@ -379,8 +379,8 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, reg->payload.len); if (val < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } break; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 05d65fbb..7ca9d842 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -173,7 +173,7 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, nft_parse_hl(ctx, e, cs); break; default: - DEBUGP("unknown payload offset %d\n", ctx->payload.offset); + DEBUGP("unknown payload offset %d\n", reg->payload.offset); break; } } -- cgit v1.2.3 From 1b7c6ffd808b05f362445f3a0a6dde5d7c217caf Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Oct 2022 15:00:09 +0200 Subject: extensions: NFQUEUE: Document queue-balance limitation The range is not communicated as "min and max queue number", but "first queue number and count" instead. With 16bits for each value, it is not possible to balance between all 65536 possible queues. Although probably never used in practice, point this detail out in man page and make the parser complain instead of the cryptic "xt_NFQUEUE: number of total queues is 0" emitted by the kernel module. Signed-off-by: Phil Sutter --- extensions/libxt_NFQUEUE.c | 2 +- extensions/libxt_NFQUEUE.man | 2 ++ extensions/libxt_NFQUEUE.t | 5 ++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c index fe519078..ca6cdaf4 100644 --- a/extensions/libxt_NFQUEUE.c +++ b/extensions/libxt_NFQUEUE.c @@ -64,7 +64,7 @@ static const struct xt_option_entry NFQUEUE_opts[] = { {.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16, .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum), .excl = F_QUEUE_BALANCE}, - {.name = "queue-balance", .id = O_QUEUE_BALANCE, + {.name = "queue-balance", .id = O_QUEUE_BALANCE, .max = UINT16_MAX - 1, .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM}, {.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE}, {.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT, diff --git a/extensions/libxt_NFQUEUE.man b/extensions/libxt_NFQUEUE.man index 1bfb7b84..950b0d24 100644 --- a/extensions/libxt_NFQUEUE.man +++ b/extensions/libxt_NFQUEUE.man @@ -18,6 +18,8 @@ This specifies a range of queues to use. Packets are then balanced across the gi This is useful for multicore systems: start multiple instances of the userspace program on queues x, x+1, .. x+n and use "\-\-queue\-balance \fIx\fP\fB:\fP\fIx+n\fP". Packets belonging to the same connection are put into the same nfqueue. +Due to implementation details, a lower range value of 0 limits the higher range +value to 65534, i.e. one can only balance between at most 65535 queues. .PP .TP \fB\-\-queue\-bypass\fP diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t index b51b19fd..5a2df6e7 100644 --- a/extensions/libxt_NFQUEUE.t +++ b/extensions/libxt_NFQUEUE.t @@ -4,9 +4,8 @@ -j NFQUEUE --queue-num 65535;=;OK -j NFQUEUE --queue-num 65536;;FAIL -j NFQUEUE --queue-num -1;;FAIL -# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1? -# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535 -# -j NFQUEUE --queue-balance 0:65535;=;OK +-j NFQUEUE --queue-balance 0:65534;=;OK +-j NFQUEUE --queue-balance 0:65535;;FAIL -j NFQUEUE --queue-balance 0:65536;;FAIL -j NFQUEUE --queue-balance -1:65535;;FAIL -j NFQUEUE --queue-num 10 --queue-bypass;=;OK -- cgit v1.2.3 From 0e80cfea3762b6680051e2b23ed69a493c762aa4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 30 Sep 2022 18:15:59 +0200 Subject: tests: iptables-test: Implement fast test mode Implement a faster mode of operation for suitable test files: 1) Collect all rules to add and all expected output in lists 2) Any supposedly failing rules are checked immediately like in slow mode. 3) Create and load iptables-restore input from the list in (1) 5) Construct the expected iptables-save output from (1) and check it in a single search 5) If any of the steps above fail, fall back to slow mode for verification and detailed error analysis. Fast mode failures are not fatal, merely warn about them. To keep things simple (and feasible), avoid complicated test files involving external commands, multiple tables or variant-specific results. Aside from speeding up testsuite run-time, rule searching has become more strict since EOL char is practically part of the search string. This revealed many false positives where the expected string was actually a substring of the printed rule. Signed-off-by: Phil Sutter --- iptables-test.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/iptables-test.py b/iptables-test.py index b5a70e44..d9b3ee4e 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -222,6 +222,153 @@ def variant_res(res, variant, alt_res=None): return alt_res return res_inverse[res] +def fast_run_possible(filename): + ''' + Keep things simple, run only for simple test files: + - no external commands + - no multiple tables + - no variant-specific results + ''' + table = None + rulecount = 0 + for line in open(filename): + if line[0] in ["#", ":"] or len(line.strip()) == 0: + continue + if line[0] == "*": + if table or rulecount > 0: + return False + table = line.rstrip()[1:] + if line[0] in ["@", "%"]: + return False + if len(line.split(";")) > 3: + return False + rulecount += 1 + + return True + +def run_test_file_fast(iptables, filename, netns): + ''' + Run a test file, but fast + + :param filename: name of the file with the test rules + :param netns: network namespace to perform test run in + ''' + + f = open(filename) + + rules = {} + table = "filter" + chain_array = [] + tests = 0 + + for lineno, line in enumerate(f): + if line[0] == "#" or len(line.strip()) == 0: + continue + + if line[0] == "*": + table = line.rstrip()[1:] + continue + + if line[0] == ":": + chain_array = line.rstrip()[1:].split(",") + continue + + if len(chain_array) == 0: + return -1 + + tests += 1 + + for chain in chain_array: + item = line.split(";") + rule = chain + " " + item[0] + + if item[1] == "=": + rule_save = chain + " " + item[0] + else: + rule_save = chain + " " + item[1] + + res = item[2].rstrip() + if res != "OK": + rule = chain + " -t " + table + " " + item[0] + ret = run_test(iptables, rule, rule_save, + res, filename, lineno + 1, netns) + + if ret < 0: + return -1 + continue + + if not chain in rules.keys(): + rules[chain] = [] + rules[chain].append((rule, rule_save)) + + restore_data = ["*" + table] + out_expect = [] + for chain in ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"]: + if not chain in rules.keys(): + continue + for rule in rules[chain]: + restore_data.append("-A " + rule[0]) + out_expect.append("-A " + rule[1]) + restore_data.append("COMMIT") + + out_expect = "\n".join(out_expect) + + # load all rules via iptables_restore + + command = EXECUTABLE + " " + iptables + "-restore" + if netns: + command = "ip netns exec " + netns + " " + command + + for line in restore_data: + print(iptables + "-restore: " + line, file=log_file) + + proc = subprocess.Popen(command, shell = True, text = True, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + restore_data = "\n".join(restore_data) + "\n" + out, err = proc.communicate(input = restore_data) + + if proc.returncode == -11: + reason = iptables + "-restore segfaults: " + cmd + print_error(reason, filename, lineno) + return -1 + + if proc.returncode != 0: + print("%s-restore returned %d: %s" % (iptables, proc.returncode, err), + file=log_file) + return -1 + + # find all rules in iptables_save output + + command = EXECUTABLE + " " + iptables + "-save" + if netns: + command = "ip netns exec " + netns + " " + command + + proc = subprocess.Popen(command, shell = True, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + out, err = proc.communicate() + + if proc.returncode == -11: + reason = iptables + "-save segfaults: " + cmd + print_error(reason, filename, lineno) + return -1 + + cmd = iptables + " -F -t " + table + execute_cmd(cmd, filename, 0, netns) + + out = out.decode('utf-8').rstrip() + if out.find(out_expect) < 0: + msg = ["dumps differ!"] + msg.extend(["expect: " + l for l in out_expect.split("\n")]) + msg.extend(["got: " + l for l in out.split("\n") + if not l[0] in ['*', ':', '#']]) + print("\n".join(msg), file=log_file) + return -1 + + return tests def run_test_file(filename, netns): ''' @@ -256,6 +403,14 @@ def run_test_file(filename, netns): # default to iptables if not known prefix iptables = IPTABLES + fast_failed = False + if fast_run_possible(filename): + tests = run_test_file_fast(iptables, filename, netns) + if tests > 0: + print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) + return tests, tests + fast_failed = True + f = open(filename) tests = 0 @@ -330,7 +485,10 @@ def run_test_file(filename, netns): if netns: execute_cmd("ip netns del " + netns, filename) if total_test_passed: - print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) + suffix = "" + if fast_failed: + suffix = maybe_colored('red', " but fast mode failed!", STDOUT_IS_TTY) + print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY) + suffix) f.close() return tests, passed -- cgit v1.2.3 From e8687835e1f9a8b4cf635239f398ef93673ebd76 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 5 Oct 2022 19:51:08 +0200 Subject: tests: iptables-test: Cover for obligatory -j CONTINUE in ebtables Unlike iptables, ebtables includes the default rule target in output. Instead of adding it to every rule in ebtables tests, add special casing to the testscript checking if the expected rule output contains a target already and adding the default one if not. Signed-off-by: Phil Sutter --- iptables-test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iptables-test.py b/iptables-test.py index d9b3ee4e..dc031c2b 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -287,6 +287,9 @@ def run_test_file_fast(iptables, filename, netns): else: rule_save = chain + " " + item[1] + if iptables == EBTABLES and rule_save.find('-j') < 0: + rule_save += " -j CONTINUE" + res = item[2].rstrip() if res != "OK": rule = chain + " -t " + table + " " + item[0] -- cgit v1.2.3 From 790d17313c19e9a6bfb2ccd9a23f7f56d62814a9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:10:34 +0200 Subject: tests: *.t: Fix expected output for simple calls These minimal extension uses print in more detailed form. Track this, the output is desired. Signed-off-by: Phil Sutter --- extensions/libebt_log.t | 2 +- extensions/libebt_nflog.t | 2 +- extensions/libip6t_REJECT.t | 2 +- extensions/libipt_REJECT.t | 2 +- extensions/libxt_NFQUEUE.t | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/libebt_log.t b/extensions/libebt_log.t index f7116c41..e6adbd3b 100644 --- a/extensions/libebt_log.t +++ b/extensions/libebt_log.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT ---log;=;OK +--log;--log-level notice;OK --log-level crit;=;OK --log-level 1;--log-level alert;OK --log-level emerg --log-ip --log-arp --log-ip6;=;OK diff --git a/extensions/libebt_nflog.t b/extensions/libebt_nflog.t index f867df30..e98d8f5f 100644 --- a/extensions/libebt_nflog.t +++ b/extensions/libebt_nflog.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT ---nflog;=;OK +--nflog;--nflog-group 1;OK --nflog-group 42;=;OK --nflog-range 42;--nflog-group 1 --nflog-range 42 -j CONTINUE;OK --nflog-threshold 100 --nflog-prefix foo;--nflog-prefix "foo" --nflog-group 1 --nflog-threshold 100 -j CONTINUE;OK diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t index d2b337d7..8294f0bb 100644 --- a/extensions/libip6t_REJECT.t +++ b/extensions/libip6t_REJECT.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --j REJECT;=;OK +-j REJECT;-j REJECT --reject-with icmp6-port-unreachable;OK # manpage for IPv6 variant of REJECT does not show up for some reason? -j REJECT --reject-with icmp6-no-route;=;OK -j REJECT --reject-with icmp6-adm-prohibited;=;OK diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t index 5b26b107..3f69a729 100644 --- a/extensions/libipt_REJECT.t +++ b/extensions/libipt_REJECT.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --j REJECT;=;OK +-j REJECT;-j REJECT --reject-with icmp-port-unreachable;OK -j REJECT --reject-with icmp-net-unreachable;=;OK -j REJECT --reject-with icmp-host-unreachable;=;OK -j REJECT --reject-with icmp-port-unreachable;=;OK diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t index 5a2df6e7..8fb2b760 100644 --- a/extensions/libxt_NFQUEUE.t +++ b/extensions/libxt_NFQUEUE.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --j NFQUEUE;=;OK +-j NFQUEUE;-j NFQUEUE --queue-num 0;OK -j NFQUEUE --queue-num 0;=;OK -j NFQUEUE --queue-num 65535;=;OK -j NFQUEUE --queue-num 65536;;FAIL -- cgit v1.2.3 From 52aa94da55a7e5f156cf9e7f608317ac53ce291c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:43:40 +0200 Subject: tests: *.t: Fix for hexadecimal output Use hex input to avoid having to specify an expected output in trivial cases. Signed-off-by: Phil Sutter --- extensions/libxt_DSCP.t | 2 +- extensions/libxt_MARK.t | 2 +- extensions/libxt_connmark.t | 4 ++-- extensions/libxt_dscp.t | 2 +- extensions/libxt_mark.t | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t index fcc55986..762fcd31 100644 --- a/extensions/libxt_DSCP.t +++ b/extensions/libxt_DSCP.t @@ -1,6 +1,6 @@ :PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING *mangle --j DSCP --set-dscp 0;=;OK +-j DSCP --set-dscp 0x00;=;OK -j DSCP --set-dscp 0x3f;=;OK -j DSCP --set-dscp -1;;FAIL -j DSCP --set-dscp 0x40;;FAIL diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t index 9d1aa7d7..2902a14f 100644 --- a/extensions/libxt_MARK.t +++ b/extensions/libxt_MARK.t @@ -1,6 +1,6 @@ :INPUT,FORWARD,OUTPUT -j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK --j MARK --set-xmark 0;=;OK +-j MARK --set-xmark 0x0;=;OK -j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK -j MARK --set-xmark 4294967296;;FAIL -j MARK --set-xmark -1;;FAIL diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t index 4dd7d9af..353970a8 100644 --- a/extensions/libxt_connmark.t +++ b/extensions/libxt_connmark.t @@ -2,8 +2,8 @@ *mangle -m connmark --mark 0xffffffff;=;OK -m connmark --mark 0xffffffff/0xffffffff;-m connmark --mark 0xffffffff;OK --m connmark --mark 0xffffffff/0;=;OK --m connmark --mark 0/0xffffffff;-m connmark --mark 0;OK +-m connmark --mark 0xffffffff/0x0;=;OK +-m connmark --mark 0/0xffffffff;-m connmark --mark 0x0;OK -m connmark --mark -1;;FAIL -m connmark --mark 0xfffffffff;;FAIL -m connmark;;FAIL diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t index 38d7f04e..e0101906 100644 --- a/extensions/libxt_dscp.t +++ b/extensions/libxt_dscp.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --m dscp --dscp 0;=;OK +-m dscp --dscp 0x00;=;OK -m dscp --dscp 0x3f;=;OK -m dscp --dscp -1;;FAIL -m dscp --dscp 0x40;;FAIL diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t index 7c005379..7aeb8715 100644 --- a/extensions/libxt_mark.t +++ b/extensions/libxt_mark.t @@ -1,6 +1,6 @@ :INPUT,FORWARD,OUTPUT -m mark --mark 0xfeedcafe/0xfeedcafe;=;OK --m mark --mark 0;=;OK +-m mark --mark 0x0;=;OK -m mark --mark 4294967295;-m mark --mark 0xffffffff;OK -m mark --mark 4294967296;;FAIL -m mark --mark -1;;FAIL -- cgit v1.2.3 From d437626ebf97d55018a2df3bf5954b6cdd2fc775 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:14:56 +0200 Subject: tests: libebt_redirect.t: Plain redirect prints with trailing whitespace Signed-off-by: Phil Sutter --- extensions/libebt_redirect.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libebt_redirect.t b/extensions/libebt_redirect.t index 23858afa..58492b79 100644 --- a/extensions/libebt_redirect.t +++ b/extensions/libebt_redirect.t @@ -1,4 +1,4 @@ :PREROUTING *nat --j redirect;=;OK +-j redirect ;=;OK -j redirect --redirect-target RETURN;=;OK -- cgit v1.2.3 From 7fb5c17796c5bceee9184bf40498b69459be69db Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 00:39:07 +0200 Subject: tests: libxt_length.t: Fix odd use-case output Specifying the lower boundary suffixed by colon is an undocumented feature. Explicitly printing the upper boundary in that case seems sane. Signed-off-by: Phil Sutter --- extensions/libxt_length.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t index 0b6624ee..8b70fc31 100644 --- a/extensions/libxt_length.t +++ b/extensions/libxt_length.t @@ -2,7 +2,7 @@ -m length --length 1;=;OK -m length --length :2;-m length --length 0:2;OK -m length --length 0:3;=;OK --m length --length 4:;=;OK +-m length --length 4:;-m length --length 4:65535;OK -m length --length 0:65535;=;OK -m length ! --length 0:65535;=;OK -m length --length 0:65536;;FAIL -- cgit v1.2.3 From 64594e06a4d85adb326ffea11b97b71255469fac Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 01:13:54 +0200 Subject: tests: libxt_recent.t: Add missing default values Signed-off-by: Phil Sutter --- extensions/libxt_recent.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_recent.t b/extensions/libxt_recent.t index 9a83918e..cf23aabc 100644 --- a/extensions/libxt_recent.t +++ b/extensions/libxt_recent.t @@ -1,8 +1,8 @@ :INPUT,FORWARD,OUTPUT --m recent --set;=;OK +-m recent --set;-m recent --set --name DEFAULT --mask 255.255.255.255 --rsource;OK -m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource;=;OK -m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK --m recent --update --rttl;=;OK +-m recent --update --rttl;-m recent --update --rttl --name DEFAULT --mask 255.255.255.255 --rsource;OK -m recent --set --rttl;;FAIL -m recent --rcheck --hitcount 999 --name foo --mask 255.255.255.255 --rsource;;FAIL # nonsensical, but all should load successfully: -- cgit v1.2.3 From 32da222e9b9cdc9269b2c1ff02be10ccb4089e4f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Oct 2022 01:25:50 +0200 Subject: tests: libxt_tos.t, libxt_TOS.t: Add missing masks in output Mask differs between numeric --set-tos values and symbolic ones, make sure it is covered by the tests. Signed-off-by: Phil Sutter --- extensions/libxt_TOS.t | 12 ++++++------ extensions/libxt_tos.t | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t index ae8531cc..9f8e33fd 100644 --- a/extensions/libxt_TOS.t +++ b/extensions/libxt_TOS.t @@ -1,15 +1,15 @@ :PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING *mangle --j TOS --set-tos 0x1f;=;OK +-j TOS --set-tos 0x1f;-j TOS --set-tos 0x1f/0xff;OK -j TOS --set-tos 0x1f/0x1f;=;OK # maximum TOS is 0x1f (5 bits) # ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff # -j TOS --set-tos 0xff;;FAIL --j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK --j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK --j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK --j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK --j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK +-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10/0x3f;OK +-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08/0x3f;OK +-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04/0x3f;OK +-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02/0x3f;OK +-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00/0x3f;OK -j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK -j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK -j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t index ccbe8009..6cceeeb4 100644 --- a/extensions/libxt_tos.t +++ b/extensions/libxt_tos.t @@ -4,10 +4,10 @@ -m tos --tos Maximize-Reliability;-m tos --tos 0x04/0x3f;OK -m tos --tos Minimize-Cost;-m tos --tos 0x02/0x3f;OK -m tos --tos Normal-Service;-m tos --tos 0x00/0x3f;OK --m tos --tos 0xff;=;OK --m tos ! --tos 0xff;=;OK --m tos --tos 0x00;=;OK --m tos --tos 0x0f;=;OK +-m tos --tos 0xff;-m tos --tos 0xff/0xff;OK +-m tos ! --tos 0xff;-m tos ! --tos 0xff/0xff;OK +-m tos --tos 0x00;-m tos --tos 0x00/0xff;OK +-m tos --tos 0x0f;-m tos --tos 0x0f/0xff;OK -m tos --tos 0x0f/0x0f;=;OK -m tos --tos wrong;;FAIL -m tos;;FAIL -- cgit v1.2.3 From 06157eab074bb538c8d7e5d0a86eeb00061705ac Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 5 Oct 2022 20:30:44 +0200 Subject: tests: libebt_vlan.t: Drop trailing whitespace from rules Fast iptables-test.py mode is picky and it has to: Plain redirect target prints a trailing whitespace, generally stripping the rules in test cases won't work therefore. Signed-off-by: Phil Sutter --- extensions/libebt_vlan.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libebt_vlan.t b/extensions/libebt_vlan.t index 81c79585..3ec05599 100644 --- a/extensions/libebt_vlan.t +++ b/extensions/libebt_vlan.t @@ -4,8 +4,8 @@ -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 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 --vlan-encap ip;=;FAIL -- cgit v1.2.3 From 53b7863296e0faade7a8bc6c1b0c9235cf4aa4d5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 5 Oct 2022 20:34:16 +0200 Subject: tests: libxt_connlimit.t: Add missing default values This extension always prints --connlimit-mask and (the default) --connlimit-saddr options. Signed-off-by: Phil Sutter --- extensions/libxt_connlimit.t | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t index c7ea61e9..366cea74 100644 --- a/extensions/libxt_connlimit.t +++ b/extensions/libxt_connlimit.t @@ -1,11 +1,11 @@ :INPUT,FORWARD,OUTPUT --m connlimit --connlimit-upto 0;=;OK --m connlimit --connlimit-upto 4294967295;=;OK --m connlimit --connlimit-upto 4294967296;;FAIL +-m connlimit --connlimit-upto 0;-m connlimit --connlimit-upto 0 --connlimit-mask 32 --connlimit-saddr;OK +-m connlimit --connlimit-upto 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK +-m connlimit --connlimit-upto 4294967296 --connlimit-mask 32 --connlimit-saddr;;FAIL -m connlimit --connlimit-upto -1;;FAIL --m connlimit --connlimit-above 0;=;OK --m connlimit --connlimit-above 4294967295;=;OK --m connlimit --connlimit-above 4294967296;;FAIL +-m connlimit --connlimit-above 0;-m connlimit --connlimit-above 0 --connlimit-mask 32 --connlimit-saddr;OK +-m connlimit --connlimit-above 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK +-m connlimit --connlimit-above 4294967296 --connlimit-mask 32 --connlimit-saddr;;FAIL -m connlimit --connlimit-above -1;;FAIL -m connlimit --connlimit-upto 1 --conlimit-above 1;;FAIL -m connlimit --connlimit-above 10 --connlimit-saddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;OK -- cgit v1.2.3 From 694f7228765b09a3e4a690a6e4c65dfbb9e15e2a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Oct 2022 16:21:17 +0200 Subject: tests: *.t: Add missing all-one's netmasks to expected output Signed-off-by: Phil Sutter --- extensions/libip6t_NETMAP.t | 2 +- extensions/libipt_NETMAP.t | 2 +- extensions/libxt_CONNMARK.t | 8 ++++---- extensions/libxt_MARK.t | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/libip6t_NETMAP.t b/extensions/libip6t_NETMAP.t index 043562d2..79d47bf6 100644 --- a/extensions/libip6t_NETMAP.t +++ b/extensions/libip6t_NETMAP.t @@ -1,4 +1,4 @@ :PREROUTING,INPUT,OUTPUT,POSTROUTING *nat -j NETMAP --to dead::/64;=;OK --j NETMAP --to dead::beef;=;OK +-j NETMAP --to dead::beef;-j NETMAP --to dead::beef/128;OK diff --git a/extensions/libipt_NETMAP.t b/extensions/libipt_NETMAP.t index 31924b98..0de856f0 100644 --- a/extensions/libipt_NETMAP.t +++ b/extensions/libipt_NETMAP.t @@ -1,4 +1,4 @@ :PREROUTING,INPUT,OUTPUT,POSTROUTING *nat -j NETMAP --to 1.2.3.0/24;=;OK --j NETMAP --to 1.2.3.4;=;OK +-j NETMAP --to 1.2.3.4;-j NETMAP --to 1.2.3.4/32;OK diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t index 79a838fe..c9b2b4a5 100644 --- a/extensions/libxt_CONNMARK.t +++ b/extensions/libxt_CONNMARK.t @@ -1,7 +1,7 @@ :PREROUTING,FORWARD,OUTPUT,POSTROUTING *mangle --j CONNMARK --restore-mark;=;OK --j CONNMARK --save-mark;=;OK --j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --save-mark;OK --j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --restore-mark;OK +-j CONNMARK --restore-mark;-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK +-j CONNMARK --save-mark;-j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK +-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK +-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK -j CONNMARK;;FAIL diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t index 2902a14f..ae026dbb 100644 --- a/extensions/libxt_MARK.t +++ b/extensions/libxt_MARK.t @@ -1,7 +1,7 @@ :INPUT,FORWARD,OUTPUT -j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK --j MARK --set-xmark 0x0;=;OK --j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK +-j MARK --set-xmark 0x0;-j MARK --set-xmark 0x0/0xffffffff;OK +-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff/0xffffffff;OK -j MARK --set-xmark 4294967296;;FAIL -j MARK --set-xmark -1;;FAIL -j MARK;;FAIL -- cgit v1.2.3 From c3432977d9a5e6c5d8e835094dc8c466a5d64f03 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 3 Jul 2022 15:59:19 +0200 Subject: extensions: DNAT: Fix bad IP address error reporting When introducing 'start' variable to cover for IPv6 addresses enclosed in brackets, this single spot was missed. Fixes: 14d77c8aa29a7 ("extensions: Merge IPv4 and IPv6 DNAT targets") Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 5696d31f..7bfefc79 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -197,7 +197,7 @@ parse_to(const char *orig_arg, bool portok, if (!inet_pton(family, start, &range->min_addr)) xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"", arg); + "Bad IP address \"%s\"", start); if (dash) { if (!inet_pton(family, dash + 1, &range->max_addr)) xtables_error(PARAMETER_PROBLEM, -- cgit v1.2.3 From 7dbd1b1dd95449b1ab8c35cd35fe904eb35db374 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Nov 2022 21:54:41 +0100 Subject: extensions: *NAT: Drop NF_NAT_RANGE_PROTO_RANDOM* flag checks SNAT, DNAT and REDIRECT extensions tried to prevent NF_NAT_RANGE_PROTO_RANDOM flag from being set if no port or address was also given. With SNAT and DNAT, this is not possible as the respective --to-destination or --to-source parameters are mandatory anyway. Looking at the kernel code, doing so with REDIRECT seems harmless. Moreover, nftables supports 'redirect random' without specifying a port-range. Signed-off-by: Phil Sutter --- extensions/libip6t_SNAT.c | 20 +++++--------------- extensions/libipt_SNAT.c | 16 ++++++---------- extensions/libxt_DNAT.c | 28 ++++------------------------ extensions/libxt_REDIRECT.t | 1 + extensions/libxt_REDIRECT.txlate | 3 +++ 5 files changed, 19 insertions(+), 49 deletions(-) diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c index 4fe272b2..8bf7b035 100644 --- a/extensions/libip6t_SNAT.c +++ b/extensions/libip6t_SNAT.c @@ -20,9 +20,6 @@ enum { O_RANDOM, O_RANDOM_FULLY, O_PERSISTENT, - F_TO_SRC = 1 << O_TO_SRC, - F_RANDOM = 1 << O_RANDOM, - F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, }; static void SNAT_help(void) @@ -166,19 +163,13 @@ static void SNAT_parse(struct xt_option_call *cb) case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; break; - } -} - -static void SNAT_fcheck(struct xt_fcheck_call *cb) -{ - static const unsigned int f = F_TO_SRC | F_RANDOM; - static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY; - struct nf_nat_range *range = cb->data; - - if ((cb->xflags & f) == f) + case O_RANDOM: range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - if ((cb->xflags & r) == r) + break; + case O_RANDOM_FULLY: range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; + } } static void print_range(const struct nf_nat_range *range) @@ -295,7 +286,6 @@ static struct xtables_target snat_tg_reg = { .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), .help = SNAT_help, .x6_parse = SNAT_parse, - .x6_fcheck = SNAT_fcheck, .print = SNAT_print, .save = SNAT_save, .x6_options = SNAT_opts, diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index 211a20bc..9c8cdb46 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -13,9 +13,6 @@ enum { O_RANDOM, O_RANDOM_FULLY, O_PERSISTENT, - F_TO_SRC = 1 << O_TO_SRC, - F_RANDOM = 1 << O_RANDOM, - F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, }; static void SNAT_help(void) @@ -141,20 +138,19 @@ static void SNAT_parse(struct xt_option_call *cb) case O_PERSISTENT: mr->range->flags |= NF_NAT_RANGE_PERSISTENT; break; + case O_RANDOM: + mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + case O_RANDOM_FULLY: + mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; } } static void SNAT_fcheck(struct xt_fcheck_call *cb) { - static const unsigned int f = F_TO_SRC | F_RANDOM; - static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY; struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - if ((cb->xflags & f) == f) - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - if ((cb->xflags & r) == r) - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - mr->rangesize = 1; } diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 7bfefc79..af445187 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -31,9 +31,6 @@ enum { O_TO_PORTS, O_RANDOM, O_PERSISTENT, - F_TO_DEST = 1 << O_TO_DEST, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, }; static void DNAT_help(void) @@ -229,6 +226,9 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; break; + case O_RANDOM: + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; } } @@ -250,21 +250,12 @@ static void DNAT_parse(struct xt_option_call *cb) mr->range->max = range.max_proto; /* fall through */ case O_PERSISTENT: + case O_RANDOM: mr->range->flags |= range.flags; break; } } -static void __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) -{ - static const unsigned int redir_f = F_TO_PORTS | F_RANDOM; - static const unsigned int dnat_f = F_TO_DEST | F_RANDOM; - - if ((cb->xflags & redir_f) == redir_f || - (cb->xflags & dnat_f) == dnat_f) - *flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - static void DNAT_fcheck(struct xt_fcheck_call *cb) { struct nf_nat_ipv4_multi_range_compat *mr = cb->data; @@ -274,8 +265,6 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) xtables_error(PARAMETER_PROBLEM, "Shifted portmap ranges not supported with this kernel"); - - __DNAT_fcheck(cb, &mr->range[0].flags); } static char *sprint_range(const struct nf_nat_range2 *r, int family) @@ -388,11 +377,6 @@ static void DNAT_parse_v2(struct xt_option_call *cb) __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); } -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - __DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags); -} - static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, int numeric) { @@ -428,8 +412,6 @@ static void DNAT_fcheck6(struct xt_fcheck_call *cb) if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) xtables_error(PARAMETER_PROBLEM, "Shifted portmap ranges not supported with this kernel"); - - __DNAT_fcheck(cb, &range->flags); } static void DNAT_print6(const void *ip, const struct xt_entry_target *target, @@ -619,7 +601,6 @@ static struct xtables_target dnat_tg_reg[] = { .print = DNAT_print_v2, .save = DNAT_save_v2, .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, .x6_options = DNAT_opts, .xlate = DNAT_xlate_v2, }, @@ -634,7 +615,6 @@ static struct xtables_target dnat_tg_reg[] = { .print = DNAT_print6_v2, .save = DNAT_save6_v2, .x6_parse = DNAT_parse6_v2, - .x6_fcheck = DNAT_fcheck_v2, .x6_options = DNAT_opts, .xlate = DNAT_xlate6_v2, }, diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t index f607dd0a..362efa84 100644 --- a/extensions/libxt_REDIRECT.t +++ b/extensions/libxt_REDIRECT.t @@ -14,3 +14,4 @@ -p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL -p tcp -j REDIRECT --to-ports 10-ssh;;FAIL -j REDIRECT --to-ports 42;;FAIL +-j REDIRECT --random;=;OK diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate index 2c536495..36419a46 100644 --- a/extensions/libxt_REDIRECT.txlate +++ b/extensions/libxt_REDIRECT.txlate @@ -16,6 +16,9 @@ nft add rule ip nat prerouting tcp dport 80 counter redirect to :10-22 iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random +iptables-translate -t nat -A prerouting -j REDIRECT --random +nft add rule ip nat prerouting counter redirect random + ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT nft add rule ip6 nat prerouting tcp dport 80 counter redirect -- cgit v1.2.3 From 586464aac30317c23a0e8508bb1fad8c27436fb2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2022 16:40:15 +0200 Subject: extensions: DNAT: Use __DNAT_xlate for REDIRECT, too Make the common function a bit more versatile and give it a more generic name, then use it for REDIRECT target, too. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index af445187..9b940625 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -338,7 +338,8 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target) } static int -__DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) +__NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, + int family, const char *tgt) { char *range_str = sprint_range(r, family); const char *sep = " "; @@ -347,7 +348,7 @@ __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) return 0; - xt_xlate_add(xl, "dnat"); + xt_xlate_add(xl, tgt); if (strlen(range_str)) xt_xlate_add(xl, " to %s", range_str); if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { @@ -367,7 +368,7 @@ static int DNAT_xlate(struct xt_xlate *xl, struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - return __DNAT_xlate(xl, &range, AF_INET); + return __NAT_xlate(xl, &range, AF_INET, "dnat"); } static void DNAT_parse_v2(struct xt_option_call *cb) @@ -391,7 +392,8 @@ static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) static int DNAT_xlate_v2(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET); + return __NAT_xlate(xl, (const void *)params->target->data, + AF_INET, "dnat"); } static void DNAT_parse6(struct xt_option_call *cb) @@ -438,7 +440,7 @@ static int DNAT_xlate6(struct xt_xlate *xl, memcpy(&range, (const void *)params->target->data, sizeof(struct nf_nat_range)); - return __DNAT_xlate(xl, &range, AF_INET6); + return __NAT_xlate(xl, &range, AF_INET6, "dnat"); } static void DNAT_parse6_v2(struct xt_option_call *cb) @@ -462,21 +464,8 @@ static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target) static int DNAT_xlate6_v2(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); -} - -static int __REDIRECT_xlate(struct xt_xlate *xl, - const struct nf_nat_range2 *range) -{ - char *range_str = sprint_range(range, AF_INET); - - xt_xlate_add(xl, "redirect"); - if (strlen(range_str)) - xt_xlate_add(xl, " to %s", range_str); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random"); - - return 1; + return __NAT_xlate(xl, (const void *)params->target->data, + AF_INET6, "dnat"); } static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, @@ -500,7 +489,7 @@ static int REDIRECT_xlate(struct xt_xlate *xl, struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - return __REDIRECT_xlate(xl, &range); + return __NAT_xlate(xl, &range, AF_INET, "redirect"); } static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target, @@ -527,7 +516,7 @@ static int REDIRECT_xlate6(struct xt_xlate *xl, memcpy(&range, (const void *)params->target->data, sizeof(struct nf_nat_range)); - return __REDIRECT_xlate(xl, &range); + return __NAT_xlate(xl, &range, AF_INET6, "redirect"); } static struct xtables_target dnat_tg_reg[] = { -- cgit v1.2.3 From 3752a0bbeb6749cc609cffe79b1ce5bd855f7965 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2022 11:01:35 +0200 Subject: extensions: DNAT: Generate print, save and xlate callbacks Each extension's callbacks follow the same scheme so introduce a generator which accepts the specifics as parameter - including the method to transform from per-extension data into struct nf_nat_range2. Also move the different parser frontends and fcheck callbacks in one spot for clarity. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.c | 266 ++++++++++++++++-------------------------------- 1 file changed, 86 insertions(+), 180 deletions(-) diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 9b940625..e5300254 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -25,6 +25,14 @@ .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ }; +#define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr)) +#define RANGE2_INIT_FROM_RANGE(ptr) { \ + .flags = TO_NF_NAT_RANGE(ptr)->flags, \ + .min_addr = TO_NF_NAT_RANGE(ptr)->min_addr, \ + .max_addr = TO_NF_NAT_RANGE(ptr)->max_addr, \ + .min_proto = TO_NF_NAT_RANGE(ptr)->min_proto, \ + .max_proto = TO_NF_NAT_RANGE(ptr)->max_proto, \ +}; enum { O_TO_DEST = 0, @@ -256,6 +264,30 @@ static void DNAT_parse(struct xt_option_call *cb) } } +static void DNAT_parse6(struct xt_option_call *cb) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data); + struct nf_nat_range *range_v1 = (void *)cb->data; + const struct ip6t_entry *entry = cb->xt_entry; + + __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); + memcpy(range_v1, &range, sizeof(*range_v1)); +} + +static void DNAT_parse_v2(struct xt_option_call *cb) +{ + const struct ipt_entry *entry = cb->xt_entry; + + __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); +} + +static void DNAT_parse6_v2(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + + __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); +} + static void DNAT_fcheck(struct xt_fcheck_call *cb) { struct nf_nat_ipv4_multi_range_compat *mr = cb->data; @@ -267,6 +299,15 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) "Shifted portmap ranges not supported with this kernel"); } +static void DNAT_fcheck6(struct xt_fcheck_call *cb) +{ + struct nf_nat_range *range = (void *)cb->data; + + if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + static char *sprint_range(const struct nf_nat_range2 *r, int family) { bool brackets = family == AF_INET6 && @@ -317,25 +358,6 @@ static void __NAT_print(const struct nf_nat_range2 *r, int family, if (r->flags & NF_NAT_RANGE_PERSISTENT) printf(" %spersistent", flag_pfx); } -#define __DNAT_print(r, family) __NAT_print(r, family, "to:", "", false) -#define __DNAT_save(r, family) __NAT_print(r, family, "--to-destination ", "--", false) -#define __REDIRECT_print(r) __NAT_print(r, AF_INET, "redir ports ", "", true) -#define __REDIRECT_save(r) __NAT_print(r, AF_INET, "--to-ports ", "--", true) - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_print(&range, AF_INET); -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_save(&range, AF_INET); -} static int __NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, @@ -362,162 +384,46 @@ __NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, return 1; } -static int DNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = - RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - - return __NAT_xlate(xl, &range, AF_INET, "dnat"); -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - - __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); -} - -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - __DNAT_print((const void *)target->data, AF_INET); -} - -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - __DNAT_save((const void *)target->data, AF_INET); -} - -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - return __NAT_xlate(xl, (const void *)params->target->data, - AF_INET, "dnat"); -} - -static void DNAT_parse6(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range_v1 = (void *)cb->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); - memcpy(range_v1, &range, sizeof(*range_v1)); -} - -static void DNAT_fcheck6(struct xt_fcheck_call *cb) -{ - struct nf_nat_range *range = (void *)cb->data; - - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - xtables_error(PARAMETER_PROBLEM, - "Shifted portmap ranges not supported with this kernel"); +#define PSX_GEN(name, converter, family, \ + print_rangeopt, save_rangeopt, skip_colon, xlate) \ +static void name##_print(const void *ip, const struct xt_entry_target *target, \ + int numeric) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, print_rangeopt, "", skip_colon); \ +} \ +static void name##_save(const void *ip, const struct xt_entry_target *target) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, save_rangeopt, "--", skip_colon); \ +} \ +static int name##_xlate(struct xt_xlate *xl, \ + const struct xt_xlate_tg_params *params) \ +{ \ + struct nf_nat_range2 range = converter(params->target->data); \ + \ + return __NAT_xlate(xl, &range, family, xlate); \ } -static void DNAT_print6(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = {}; +PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-destination ", false, "dnat") - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_print(&range, AF_INET6); -} +PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \ + AF_INET, "to:", "--to-destination ", false, "dnat") -static void DNAT_save6(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_save(&range, AF_INET6); -} - -static int DNAT_xlate6(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)params->target->data, - sizeof(struct nf_nat_range)); - return __NAT_xlate(xl, &range, AF_INET6, "dnat"); -} +PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-destination ", false, "dnat") -static void DNAT_parse6_v2(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - - __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); -} +PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \ + AF_INET6, "to:", "--to-destination ", false, "dnat") -static void DNAT_print6_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - __DNAT_print((const void *)target->data, AF_INET6); -} +PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "redir ports ", "--to-ports ", true, "redirect") -static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target) -{ - __DNAT_save((const void *)target->data, AF_INET6); -} - -static int DNAT_xlate6_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - return __NAT_xlate(xl, (const void *)params->target->data, - AF_INET6, "dnat"); -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __REDIRECT_print(&range); -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __REDIRECT_save(&range); -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = - RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - - return __NAT_xlate(xl, &range, AF_INET, "redirect"); -} - -static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_print(&range); -} - -static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_save(&range); -} - -static int REDIRECT_xlate6(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)params->target->data, - sizeof(struct nf_nat_range)); - return __NAT_xlate(xl, &range, AF_INET6, "redirect"); -} +PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "redir ports ", "--to-ports ", true, "redirect") static struct xtables_target dnat_tg_reg[] = { { @@ -558,12 +464,12 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), .help = DNAT_help, - .print = DNAT_print6, - .save = DNAT_save6, + .print = DNAT6_print, + .save = DNAT6_save, .x6_parse = DNAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = DNAT_opts, - .xlate = DNAT_xlate6, + .xlate = DNAT6_xlate, }, { .name = "REDIRECT", @@ -572,12 +478,12 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), .help = REDIRECT_help, - .print = REDIRECT_print6, - .save = REDIRECT_save6, + .print = REDIRECT6_print, + .save = REDIRECT6_save, .x6_parse = DNAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate6, + .xlate = REDIRECT6_xlate, }, { .name = "DNAT", @@ -587,11 +493,11 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range2)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), .help = DNAT_help_v2, - .print = DNAT_print_v2, - .save = DNAT_save_v2, + .print = DNATv2_print, + .save = DNATv2_save, .x6_parse = DNAT_parse_v2, .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, + .xlate = DNATv2_xlate, }, { .name = "DNAT", @@ -601,11 +507,11 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range2)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), .help = DNAT_help_v2, - .print = DNAT_print6_v2, - .save = DNAT_save6_v2, + .print = DNAT6v2_print, + .save = DNAT6v2_save, .x6_parse = DNAT_parse6_v2, .x6_options = DNAT_opts, - .xlate = DNAT_xlate6_v2, + .xlate = DNAT6v2_xlate, }, }; -- cgit v1.2.3 From 0c0807bed45568b458980e65691ec4482aeb1cf3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Nov 2022 23:21:29 +0100 Subject: extensions: DNAT: Rename some symbols No functional change intended, just a more generic name for some symbols which won't be DNAT-specific soon. Signed-off-by: Phil Sutter --- extensions/libxt_DNAT.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index e5300254..fbb10e41 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -214,8 +214,8 @@ parse_to(const char *orig_arg, bool portok, return; } -static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, - struct nf_nat_range2 *range, int family) +static void __NAT_parse(struct xt_option_call *cb, __u16 proto, + struct nf_nat_range2 *range, int family) { bool portok = proto == IPPROTO_TCP || proto == IPPROTO_UDP || @@ -240,13 +240,13 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, } } -static void DNAT_parse(struct xt_option_call *cb) +static void NAT_parse(struct xt_option_call *cb) { struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; const struct ipt_entry *entry = cb->xt_entry; struct nf_nat_range2 range = {}; - __DNAT_parse(cb, entry->ip.proto, &range, AF_INET); + __NAT_parse(cb, entry->ip.proto, &range, AF_INET); switch (cb->entry->id) { case O_TO_DEST: @@ -264,13 +264,13 @@ static void DNAT_parse(struct xt_option_call *cb) } } -static void DNAT_parse6(struct xt_option_call *cb) +static void NAT_parse6(struct xt_option_call *cb) { struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data); struct nf_nat_range *range_v1 = (void *)cb->data; const struct ip6t_entry *entry = cb->xt_entry; - __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); + __NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); memcpy(range_v1, &range, sizeof(*range_v1)); } @@ -278,14 +278,14 @@ static void DNAT_parse_v2(struct xt_option_call *cb) { const struct ipt_entry *entry = cb->xt_entry; - __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); + __NAT_parse(cb, entry->ip.proto, cb->data, AF_INET); } static void DNAT_parse6_v2(struct xt_option_call *cb) { const struct ip6t_entry *entry = cb->xt_entry; - __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); + __NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); } static void DNAT_fcheck(struct xt_fcheck_call *cb) @@ -425,7 +425,7 @@ PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ AF_INET6, "redir ports ", "--to-ports ", true, "redirect") -static struct xtables_target dnat_tg_reg[] = { +static struct xtables_target nat_tg_reg[] = { { .name = "DNAT", .version = XTABLES_VERSION, @@ -436,7 +436,7 @@ static struct xtables_target dnat_tg_reg[] = { .help = DNAT_help, .print = DNAT_print, .save = DNAT_save, - .x6_parse = DNAT_parse, + .x6_parse = NAT_parse, .x6_fcheck = DNAT_fcheck, .x6_options = DNAT_opts, .xlate = DNAT_xlate, @@ -451,7 +451,7 @@ static struct xtables_target dnat_tg_reg[] = { .help = REDIRECT_help, .print = REDIRECT_print, .save = REDIRECT_save, - .x6_parse = DNAT_parse, + .x6_parse = NAT_parse, .x6_fcheck = DNAT_fcheck, .x6_options = REDIRECT_opts, .xlate = REDIRECT_xlate, @@ -466,7 +466,7 @@ static struct xtables_target dnat_tg_reg[] = { .help = DNAT_help, .print = DNAT6_print, .save = DNAT6_save, - .x6_parse = DNAT_parse6, + .x6_parse = NAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = DNAT_opts, .xlate = DNAT6_xlate, @@ -480,7 +480,7 @@ static struct xtables_target dnat_tg_reg[] = { .help = REDIRECT_help, .print = REDIRECT6_print, .save = REDIRECT6_save, - .x6_parse = DNAT_parse6, + .x6_parse = NAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = REDIRECT_opts, .xlate = REDIRECT6_xlate, @@ -517,5 +517,5 @@ static struct xtables_target dnat_tg_reg[] = { void _init(void) { - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); + xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg)); } -- cgit v1.2.3 From f30c5edce0413b2b2346c7f58e801f10f6e9bc5a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 12 Apr 2022 21:19:39 +0200 Subject: extensions: Merge SNAT, DNAT, REDIRECT and MASQUERADE REDIRECT was already merged into DNAT. Given the callback generator and generalized inner parsing routines, merging the other "flavors" is relatively simple. Rename the extension into "libxt_NAT.so" while doing so and turn the old DSOs into symlinks. Signed-off-by: Phil Sutter --- extensions/GNUmakefile.in | 10 +- extensions/libip6t_MASQUERADE.c | 188 ---------- extensions/libip6t_MASQUERADE.txlate | 9 + extensions/libip6t_SNAT.c | 298 ---------------- extensions/libip6t_SNAT.t | 6 + extensions/libipt_MASQUERADE.c | 190 ----------- extensions/libipt_MASQUERADE.txlate | 9 + extensions/libipt_SNAT.c | 276 --------------- extensions/libipt_SNAT.t | 6 + extensions/libxt_DNAT.c | 521 ---------------------------- extensions/libxt_NAT.c | 646 +++++++++++++++++++++++++++++++++++ 11 files changed, 684 insertions(+), 1475 deletions(-) delete mode 100644 extensions/libip6t_MASQUERADE.c delete mode 100644 extensions/libip6t_SNAT.c delete mode 100644 extensions/libipt_MASQUERADE.c delete mode 100644 extensions/libipt_SNAT.c delete mode 100644 extensions/libxt_DNAT.c create mode 100644 extensions/libxt_NAT.c diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 3c68f8de..0239a06a 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -42,7 +42,7 @@ endif pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) @ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c))) @ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c))) -pfx_symlinks := NOTRACK state REDIRECT +pfx_symlinks := NOTRACK state REDIRECT MASQUERADE SNAT DNAT @ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c))) @ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c))) pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod}) @@ -130,7 +130,13 @@ libxt_NOTRACK.so: libxt_CT.so ln -fs $< $@ libxt_state.so: libxt_conntrack.so ln -fs $< $@ -libxt_REDIRECT.so: libxt_DNAT.so +libxt_REDIRECT.so: libxt_NAT.so + ln -fs $< $@ +libxt_MASQUERADE.so: libxt_NAT.so + ln -fs $< $@ +libxt_SNAT.so: libxt_NAT.so + ln -fs $< $@ +libxt_DNAT.so: libxt_NAT.so ln -fs $< $@ # Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c deleted file mode 100644 index f28f071b..00000000 --- a/extensions/libip6t_MASQUERADE.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy - * - * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include -#include -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_PORTS = 0, - O_RANDOM, - O_RANDOM_FULLY, -}; - -static void MASQUERADE_help(void) -{ - printf( -"MASQUERADE target options:\n" -" --to-ports [-]\n" -" Port (range) to map to.\n" -" --random\n" -" Randomize source port.\n" -" --random-fully\n" -" Fully randomize source port.\n"); -} - -static const struct xt_option_entry MASQUERADE_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_range *r) -{ - char *end; - unsigned int port, maxport; - - r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); - - switch (*end) { - case '\0': - r->min_proto.tcp.port - = r->max_proto.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) - break; - - if (maxport < port) - break; - - r->min_proto.tcp.port = htons(port); - r->max_proto.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); -} - -static void MASQUERADE_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *r = cb->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, r); - break; - case O_RANDOM: - r->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - r->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void -MASQUERADE_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *r = (const void *)target->data; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" masq ports: "); - printf("%hu", ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - printf("-%hu", ntohs(r->max_proto.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); -} - -static void -MASQUERADE_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *r = (const void *)target->data; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - printf("-%hu", ntohs(r->max_proto.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); -} - -static int MASQUERADE_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *r = (const void *)params->target->data; - - xt_xlate_add(xl, "masquerade"); - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port)); - } - - xt_xlate_add(xl, " "); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, "random "); - - xt_xlate_add(xl, " "); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - xt_xlate_add(xl, "fully-random "); - - return 1; -} - -static struct xtables_target masquerade_tg_reg = { - .name = "MASQUERADE", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = MASQUERADE_help, - .x6_parse = MASQUERADE_parse, - .print = MASQUERADE_print, - .save = MASQUERADE_save, - .x6_options = MASQUERADE_opts, - .xlate = MASQUERADE_xlate, -}; - -void _init(void) -{ - xtables_register_target(&masquerade_tg_reg); -} diff --git a/extensions/libip6t_MASQUERADE.txlate b/extensions/libip6t_MASQUERADE.txlate index 6c289c2b..a2f98080 100644 --- a/extensions/libip6t_MASQUERADE.txlate +++ b/extensions/libip6t_MASQUERADE.txlate @@ -6,3 +6,12 @@ nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10 ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random +nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully +nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade fully-random + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully +nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random,fully-random diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c deleted file mode 100644 index 8bf7b035..00000000 --- a/extensions/libip6t_SNAT.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy - * - * Based on Rusty Russell's IPv4 SNAT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include -#include -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_SRC = 0, - O_RANDOM, - O_RANDOM_FULLY, - O_PERSISTENT, -}; - -static void SNAT_help(void) -{ - printf( -"SNAT target options:\n" -" --to-source [[-]][:port[-port]]\n" -" Address to map source to.\n" -"[--random] [--random-fully] [--persistent]\n"); -} - -static const struct xt_option_entry SNAT_opts[] = { - {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, - .flags = XTOPT_MAND}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) -{ - char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; - const struct in6_addr *ip; - - arg = xtables_strdup(orig_arg); - - start = strchr(arg, '['); - if (start == NULL) { - start = arg; - /* Lets assume one colon is port information. Otherwise its an IPv6 address */ - colon = strchr(arg, ':'); - if (colon && strchr(colon+1, ':')) - colon = NULL; - } - else { - start++; - end = strchr(start, ']'); - if (end == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid address format"); - - *end = '\0'; - colon = strchr(end + 1, ':'); - } - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - } - /* Starts with colon or [] colon? No IP info...*/ - if (colon == arg || colon == arg+2) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(start, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ip6addr(start); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - start); - range->min_addr.in6 = *ip; - if (dash) { - ip = xtables_numeric_to_ip6addr(dash + 1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in6 = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - -static void SNAT_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range = cb->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_SRC: - parse_to(cb->arg, portok, range); - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - case O_RANDOM: - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void print_range(const struct nf_nat_range *range) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("["); - printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("]"); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - } -} - -static void SNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range = (const void *)target->data; - - printf(" to:"); - print_range(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); -} - -static void SNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range = (const void *)target->data; - - printf(" --to-source "); - print_range(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); -} - -static void print_range_xlate(const struct nf_nat_range *range, - struct xt_xlate *xl) -{ - bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED; - - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - xt_xlate_add(xl, "%s%s%s", - proto_specified ? "[" : "", - xtables_ip6addr_to_numeric(&range->min_addr.in6), - proto_specified ? "]" : ""); - - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) { - xt_xlate_add(xl, "-%s%s%s", - proto_specified ? "[" : "", - xtables_ip6addr_to_numeric(&range->max_addr.in6), - proto_specified ? "]" : ""); - } - } - if (proto_specified) { - xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port)); - - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu", - ntohs(range->max_proto.tcp.port)); - } -} - -static int SNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *range = (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "snat to "); - print_range_xlate(range, xl); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%sfully-random", sep); - sep_need = true; - } - if (range->flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } - - return 1; -} - -static struct xtables_target snat_tg_reg = { - .name = "SNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 1, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = SNAT_help, - .x6_parse = SNAT_parse, - .print = SNAT_print, - .save = SNAT_save, - .x6_options = SNAT_opts, - .xlate = SNAT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&snat_tg_reg); -} diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t index d188a6bb..98aa7602 100644 --- a/extensions/libip6t_SNAT.t +++ b/extensions/libip6t_SNAT.t @@ -4,6 +4,12 @@ -j SNAT --to-source dead::beef-dead::fee7;=;OK -j SNAT --to-source [dead::beef]:1025-65535;;FAIL -j SNAT --to-source [dead::beef] --to-source [dead::fee7];;FAIL +-j SNAT --to-source dead::beef --random;=;OK +-j SNAT --to-source dead::beef --random-fully;=;OK +-j SNAT --to-source dead::beef --persistent;=;OK +-j SNAT --to-source dead::beef --random --persistent;=;OK +-j SNAT --to-source dead::beef --random --random-fully;=;OK +-j SNAT --to-source dead::beef --random --random-fully --persistent;=;OK -p tcp -j SNAT --to-source [dead::beef]:1025-65535;=;OK -p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535;=;OK -p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65536;;FAIL diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c deleted file mode 100644 index 90bf6065..00000000 --- a/extensions/libipt_MASQUERADE.c +++ /dev/null @@ -1,190 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_PORTS = 0, - O_RANDOM, - O_RANDOM_FULLY, -}; - -static void MASQUERADE_help(void) -{ - printf( -"MASQUERADE target options:\n" -" --to-ports [-]\n" -" Port (range) to map to.\n" -" --random\n" -" Randomize source port.\n" -" --random-fully\n" -" Fully randomize source port.\n"); -} - -static const struct xt_option_entry MASQUERADE_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static void MASQUERADE_init(struct xt_entry_target *t) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; - - /* Actually, it's 0, but it's ignored at the moment. */ - mr->rangesize = 1; -} - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) -{ - char *end; - unsigned int port, maxport; - - mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); - - switch (*end) { - case '\0': - mr->range[0].min.tcp.port - = mr->range[0].max.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) - break; - - if (maxport < port) - break; - - mr->range[0].min.tcp.port = htons(port); - mr->range[0].max.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); -} - -static void MASQUERADE_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - int portok; - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, mr); - break; - case O_RANDOM: - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void -MASQUERADE_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" masq ports: "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); -} - -static void -MASQUERADE_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports %hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); -} - -static int MASQUERADE_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - xt_xlate_add(xl, "masquerade"); - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, " to :%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port)); - } - - xt_xlate_add(xl, " "); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, "random "); - - return 1; -} - -static struct xtables_target masquerade_tg_reg = { - .name = "MASQUERADE", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = MASQUERADE_help, - .init = MASQUERADE_init, - .x6_parse = MASQUERADE_parse, - .print = MASQUERADE_print, - .save = MASQUERADE_save, - .x6_options = MASQUERADE_opts, - .xlate = MASQUERADE_xlate, -}; - -void _init(void) -{ - xtables_register_target(&masquerade_tg_reg); -} diff --git a/extensions/libipt_MASQUERADE.txlate b/extensions/libipt_MASQUERADE.txlate index 40b6958a..49f79d33 100644 --- a/extensions/libipt_MASQUERADE.txlate +++ b/extensions/libipt_MASQUERADE.txlate @@ -6,3 +6,12 @@ nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10 iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random +nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade random + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully +nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade fully-random + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully +nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade random,fully-random diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c deleted file mode 100644 index 9c8cdb46..00000000 --- a/extensions/libipt_SNAT.c +++ /dev/null @@ -1,276 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include /* INT_MAX in ip_tables.h */ -#include -#include - -enum { - O_TO_SRC = 0, - O_RANDOM, - O_RANDOM_FULLY, - O_PERSISTENT, -}; - -static void SNAT_help(void) -{ - printf( -"SNAT target options:\n" -" --to-source [[-]][:port[-port]]\n" -" Address to map source to.\n" -"[--random] [--random-fully] [--persistent]\n"); -} - -static const struct xt_option_entry SNAT_opts[] = { - {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, - .flags = XTOPT_MAND}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range) -{ - char *arg, *colon, *dash, *error; - const struct in_addr *ip; - - arg = xtables_strdup(orig_arg); - colon = strchr(arg, ':'); - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min.tcp.port - = range->max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min.tcp.port = htons(port); - range->max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range->min_ip = ip->s_addr; - if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_ip = ip->s_addr; - } else - range->max_ip = range->min_ip; - - free(arg); - return; -} - -static void SNAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - const struct ipt_entry *entry = cb->xt_entry; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_SRC: - parse_to(cb->arg, portok, mr->range); - break; - case O_PERSISTENT: - mr->range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - case O_RANDOM: - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void SNAT_fcheck(struct xt_fcheck_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - mr->rangesize = 1; -} - -static void print_range(const struct nf_nat_ipv4_range *r) -{ - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; - - a.s_addr = r->min_ip; - printf("%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - printf("-%s", xtables_ipaddr_to_numeric(&a)); - } - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } -} - -static void SNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" to:"); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); -} - -static void SNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" --to-source "); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); -} - -static void print_range_xlate(const struct nf_nat_ipv4_range *r, - struct xt_xlate *xl) -{ - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; - - a.s_addr = r->min_ip; - xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a)); - } - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, ":"); - xt_xlate_add(xl, "%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port)); - } -} - -static int SNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "snat to "); - print_range_xlate(mr->range, xl); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%sfully-random", sep); - sep_need = true; - } - if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%spersistent", sep); - } - - return 1; -} - -static struct xtables_target snat_tg_reg = { - .name = "SNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = SNAT_help, - .x6_parse = SNAT_parse, - .x6_fcheck = SNAT_fcheck, - .print = SNAT_print, - .save = SNAT_save, - .x6_options = SNAT_opts, - .xlate = SNAT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&snat_tg_reg); -} diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t index 186e1cb8..c31d6e7c 100644 --- a/extensions/libipt_SNAT.t +++ b/extensions/libipt_SNAT.t @@ -4,6 +4,12 @@ -j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK -j SNAT --to-source 1.1.1.1:1025-65535;;FAIL -j SNAT --to-source 1.1.1.1 --to-source 2.2.2.2;;FAIL +-j SNAT --to-source 1.1.1.1 --random;=;OK +-j SNAT --to-source 1.1.1.1 --random-fully;=;OK +-j SNAT --to-source 1.1.1.1 --persistent;=;OK +-j SNAT --to-source 1.1.1.1 --random --persistent;=;OK +-j SNAT --to-source 1.1.1.1 --random --random-fully;=;OK +-j SNAT --to-source 1.1.1.1 --random --random-fully --persistent;=;OK -p tcp -j SNAT --to-source 1.1.1.1:1025-65535;=;OK -p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535;=;OK -p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65536;;FAIL diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c deleted file mode 100644 index fbb10e41..00000000 --- a/extensions/libxt_DNAT.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy - * - * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include -#include -#include -#include -#include -#include /* get_kernel_version */ -#include /* INT_MAX in ip_tables.h */ -#include -#include -#include -#include - -#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) -#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ - .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ - .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ - .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ - .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ - .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ -}; -#define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr)) -#define RANGE2_INIT_FROM_RANGE(ptr) { \ - .flags = TO_NF_NAT_RANGE(ptr)->flags, \ - .min_addr = TO_NF_NAT_RANGE(ptr)->min_addr, \ - .max_addr = TO_NF_NAT_RANGE(ptr)->max_addr, \ - .min_proto = TO_NF_NAT_RANGE(ptr)->min_proto, \ - .max_proto = TO_NF_NAT_RANGE(ptr)->max_proto, \ -}; - -enum { - O_TO_DEST = 0, - O_TO_PORTS, - O_RANDOM, - O_PERSISTENT, -}; - -static void DNAT_help(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void DNAT_help_v2(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [[-]][:port[-port[/port]]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports [-]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry DNAT_opts[] = { - {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) -{ - unsigned int port, maxport, baseport; - char *end = NULL; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) { - port = xtables_service_to_port(arg, NULL); - if (port == (unsigned)-1) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); - end = ""; - } - - switch (*end) { - case '\0': - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - return; - case '-': - arg = end + 1; - break; - case ':': - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash"); - default: - xtables_error(PARAMETER_PROBLEM, - "Garbage after port value: `%s'", end); - } - - /* it is a range, don't allow service names here */ - if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg); - - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky", arg); - - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - switch (*end) { - case '\0': - return; - case '/': - arg = end + 1; - break; - default: - xtables_error(PARAMETER_PROBLEM, - "Garbage after port range: `%s'", end); - } - - if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) { - baseport = xtables_service_to_port(arg, NULL); - if (baseport == (unsigned)-1) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); - } - - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); -} - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, bool portok, - struct nf_nat_range2 *range, int family) -{ - char *arg, *start, *end, *colon, *dash; - - arg = xtables_strdup(orig_arg); - start = strchr(arg, '['); - if (!start) { - start = arg; - /* Lets assume one colon is port information. - * Otherwise its an IPv6 address */ - colon = strchr(arg, ':'); - if (colon && strchr(colon + 1, ':')) - colon = NULL; - } else { - start++; - end = strchr(start, ']'); - if (end == NULL || family == AF_INET) - xtables_error(PARAMETER_PROBLEM, - "Invalid address format"); - - *end = '\0'; - colon = strchr(end + 1, ':'); - } - - if (colon) { - parse_ports(colon + 1, portok, range); - - /* Starts with colon or [] colon? No IP info...*/ - if (colon == arg || colon == arg + 2) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(start, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - if (!inet_pton(family, start, &range->min_addr)) - xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"", start); - if (dash) { - if (!inet_pton(family, dash + 1, &range->max_addr)) - xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"", dash + 1); - } else { - range->max_addr = range->min_addr; - } - free(arg); - return; -} - -static void __NAT_parse(struct xt_option_call *cb, __u16 proto, - struct nf_nat_range2 *range, int family) -{ - bool portok = proto == IPPROTO_TCP || - proto == IPPROTO_UDP || - proto == IPPROTO_SCTP || - proto == IPPROTO_DCCP || - proto == IPPROTO_ICMP; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - parse_to(cb->arg, portok, range, family); - break; - case O_TO_PORTS: - parse_ports(cb->arg, portok, range); - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - case O_RANDOM: - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void NAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_range2 range = {}; - - __NAT_parse(cb, entry->ip.proto, &range, AF_INET); - - switch (cb->entry->id) { - case O_TO_DEST: - mr->range->min_ip = range.min_addr.ip; - mr->range->max_ip = range.max_addr.ip; - /* fall through */ - case O_TO_PORTS: - mr->range->min = range.min_proto; - mr->range->max = range.max_proto; - /* fall through */ - case O_PERSISTENT: - case O_RANDOM: - mr->range->flags |= range.flags; - break; - } -} - -static void NAT_parse6(struct xt_option_call *cb) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data); - struct nf_nat_range *range_v1 = (void *)cb->data; - const struct ip6t_entry *entry = cb->xt_entry; - - __NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); - memcpy(range_v1, &range, sizeof(*range_v1)); -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - - __NAT_parse(cb, entry->ip.proto, cb->data, AF_INET); -} - -static void DNAT_parse6_v2(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - - __NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); -} - -static void DNAT_fcheck(struct xt_fcheck_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - mr->rangesize = 1; - - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) - xtables_error(PARAMETER_PROBLEM, - "Shifted portmap ranges not supported with this kernel"); -} - -static void DNAT_fcheck6(struct xt_fcheck_call *cb) -{ - struct nf_nat_range *range = (void *)cb->data; - - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - xtables_error(PARAMETER_PROBLEM, - "Shifted portmap ranges not supported with this kernel"); -} - -static char *sprint_range(const struct nf_nat_range2 *r, int family) -{ - bool brackets = family == AF_INET6 && - r->flags & NF_NAT_RANGE_PROTO_SPECIFIED; - static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3]; - - buf[0] = '\0'; - - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - if (brackets) - strcat(buf, "["); - inet_ntop(family, &r->min_addr, - buf + strlen(buf), INET6_ADDRSTRLEN); - if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) { - strcat(buf, "-"); - inet_ntop(family, &r->max_addr, - buf + strlen(buf), INET6_ADDRSTRLEN); - } - if (brackets) - strcat(buf, "]"); - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - sprintf(buf + strlen(buf), ":%hu", - ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - sprintf(buf + strlen(buf), "-%hu", - ntohs(r->max_proto.tcp.port)); - if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) - sprintf(buf + strlen(buf), "/%hu", - ntohs(r->base_proto.tcp.port)); - } - return buf; -} - -static void __NAT_print(const struct nf_nat_range2 *r, int family, - const char *rangeopt, const char *flag_pfx, - bool skip_colon) -{ - char *range_str = sprint_range(r, family); - - if (strlen(range_str)) { - if (range_str[0] == ':' && skip_colon) - range_str++; - printf(" %s%s", rangeopt, range_str); - } - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" %srandom", flag_pfx); - if (r->flags & NF_NAT_RANGE_PERSISTENT) - printf(" %spersistent", flag_pfx); -} - -static int -__NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, - int family, const char *tgt) -{ - char *range_str = sprint_range(r, family); - const char *sep = " "; - - /* shifted portmap ranges are not supported by nftables */ - if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) - return 0; - - xt_xlate_add(xl, tgt); - if (strlen(range_str)) - xt_xlate_add(xl, " to %s", range_str); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, "%srandom", sep); - sep = ","; - } - if (r->flags & NF_NAT_RANGE_PERSISTENT) { - xt_xlate_add(xl, "%spersistent", sep); - sep = ","; - } - return 1; -} - -#define PSX_GEN(name, converter, family, \ - print_rangeopt, save_rangeopt, skip_colon, xlate) \ -static void name##_print(const void *ip, const struct xt_entry_target *target, \ - int numeric) \ -{ \ - struct nf_nat_range2 range = converter(target->data); \ - \ - __NAT_print(&range, family, print_rangeopt, "", skip_colon); \ -} \ -static void name##_save(const void *ip, const struct xt_entry_target *target) \ -{ \ - struct nf_nat_range2 range = converter(target->data); \ - \ - __NAT_print(&range, family, save_rangeopt, "--", skip_colon); \ -} \ -static int name##_xlate(struct xt_xlate *xl, \ - const struct xt_xlate_tg_params *params) \ -{ \ - struct nf_nat_range2 range = converter(params->target->data); \ - \ - return __NAT_xlate(xl, &range, family, xlate); \ -} - -PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \ - AF_INET, "to:", "--to-destination ", false, "dnat") - -PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \ - AF_INET, "to:", "--to-destination ", false, "dnat") - -PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \ - AF_INET6, "to:", "--to-destination ", false, "dnat") - -PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \ - AF_INET6, "to:", "--to-destination ", false, "dnat") - -PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ - AF_INET, "redir ports ", "--to-ports ", true, "redirect") - -PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ - AF_INET6, "redir ports ", "--to-ports ", true, "redirect") - -static struct xtables_target nat_tg_reg[] = { - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 0, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = DNAT_help, - .print = DNAT_print, - .save = DNAT_save, - .x6_parse = NAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate, - }, - { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 0, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = REDIRECT_help, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_parse = NAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 1, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = DNAT_help, - .print = DNAT6_print, - .save = DNAT6_save, - .x6_parse = NAT_parse6, - .x6_fcheck = DNAT_fcheck6, - .x6_options = DNAT_opts, - .xlate = DNAT6_xlate, - }, - { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = REDIRECT_help, - .print = REDIRECT6_print, - .save = REDIRECT6_save, - .x6_parse = NAT_parse6, - .x6_fcheck = DNAT_fcheck6, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT6_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNATv2_print, - .save = DNATv2_save, - .x6_parse = DNAT_parse_v2, - .x6_options = DNAT_opts, - .xlate = DNATv2_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNAT6v2_print, - .save = DNAT6v2_save, - .x6_parse = DNAT_parse6_v2, - .x6_options = DNAT_opts, - .xlate = DNAT6v2_xlate, - }, -}; - -void _init(void) -{ - xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg)); -} diff --git a/extensions/libxt_NAT.c b/extensions/libxt_NAT.c new file mode 100644 index 00000000..da9f2201 --- /dev/null +++ b/extensions/libxt_NAT.c @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2011 Patrick McHardy + * + * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include +#include +#include +#include +#include +#include /* get_kernel_version */ +#include /* INT_MAX in ip_tables.h */ +#include +#include +#include +#include + +#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) +#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ + .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ + .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ + .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ + .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ + .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ +}; +#define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr)) +#define RANGE2_INIT_FROM_RANGE(ptr) { \ + .flags = TO_NF_NAT_RANGE(ptr)->flags, \ + .min_addr = TO_NF_NAT_RANGE(ptr)->min_addr, \ + .max_addr = TO_NF_NAT_RANGE(ptr)->max_addr, \ + .min_proto = TO_NF_NAT_RANGE(ptr)->min_proto, \ + .max_proto = TO_NF_NAT_RANGE(ptr)->max_proto, \ +}; + +enum { + O_TO_DEST = 0, + O_TO_SRC, + O_TO_PORTS, + O_RANDOM, + O_RANDOM_FULLY, + O_PERSISTENT, +}; + +static void SNAT_help(void) +{ + printf( +"SNAT target options:\n" +" --to-source [[-]][:port[-port]]\n" +" Address to map source to.\n" +"[--random] [--random-fully] [--persistent]\n"); +} + +static void MASQUERADE_help(void) +{ + printf( +"MASQUERADE target options:\n" +" --to-ports [-]\n" +" Port (range) to map to.\n" +" --random\n" +" Randomize source port.\n" +" --random-fully\n" +" Fully randomize source port.\n"); +} + +static void DNAT_help(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [[-]][:port[-port]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static void DNAT_help_v2(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [[-]][:port[-port[/port]]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static void REDIRECT_help(void) +{ + printf( +"REDIRECT target options:\n" +" --to-ports [-]\n" +" Port (range) to map to.\n" +" [--random]\n"); +} + +static const struct xt_option_entry SNAT_opts[] = { + {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry MASQUERADE_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry DNAT_opts[] = { + {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Parses ports */ +static void +parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) +{ + unsigned int port, maxport, baseport; + char *end = NULL; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) { + port = xtables_service_to_port(arg, NULL); + if (port == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + end = ""; + } + + switch (*end) { + case '\0': + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + return; + case '-': + arg = end + 1; + break; + case ':': + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash"); + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port value: `%s'", end); + } + + /* it is a range, don't allow service names here */ + if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg); + + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky", arg); + + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + + switch (*end) { + case '\0': + return; + case '/': + arg = end + 1; + break; + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port range: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) { + baseport = xtables_service_to_port(arg, NULL); + if (baseport == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + } + + range->flags |= NF_NAT_RANGE_PROTO_OFFSET; + range->base_proto.tcp.port = htons(baseport); +} + +/* Ranges expected in network order. */ +static void +parse_to(const char *orig_arg, bool portok, + struct nf_nat_range2 *range, int family) +{ + char *arg, *start, *end, *colon, *dash; + + arg = xtables_strdup(orig_arg); + start = strchr(arg, '['); + if (!start) { + start = arg; + /* Lets assume one colon is port information. + * Otherwise its an IPv6 address */ + colon = strchr(arg, ':'); + if (colon && strchr(colon + 1, ':')) + colon = NULL; + } else { + start++; + end = strchr(start, ']'); + if (end == NULL || family == AF_INET) + xtables_error(PARAMETER_PROBLEM, + "Invalid address format"); + + *end = '\0'; + colon = strchr(end + 1, ':'); + } + + if (colon) { + parse_ports(colon + 1, portok, range); + + /* Starts with colon or [] colon? No IP info...*/ + if (colon == arg || colon == arg + 2) { + free(arg); + return; + } + *colon = '\0'; + } + + range->flags |= NF_NAT_RANGE_MAP_IPS; + dash = strchr(start, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + if (!inet_pton(family, start, &range->min_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"", start); + if (dash) { + if (!inet_pton(family, dash + 1, &range->max_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"", dash + 1); + } else { + range->max_addr = range->min_addr; + } + free(arg); + return; +} + +static void __NAT_parse(struct xt_option_call *cb, __u16 proto, + struct nf_nat_range2 *range, int family) +{ + bool portok = proto == IPPROTO_TCP || + proto == IPPROTO_UDP || + proto == IPPROTO_SCTP || + proto == IPPROTO_DCCP || + proto == IPPROTO_ICMP; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + case O_TO_SRC: + parse_to(cb->arg, portok, range, family); + break; + case O_TO_PORTS: + parse_ports(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + case O_RANDOM: + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + case O_RANDOM_FULLY: + range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; + } +} + +static void NAT_parse(struct xt_option_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; + const struct ipt_entry *entry = cb->xt_entry; + struct nf_nat_range2 range = {}; + + __NAT_parse(cb, entry->ip.proto, &range, AF_INET); + + switch (cb->entry->id) { + case O_TO_DEST: + case O_TO_SRC: + mr->range->min_ip = range.min_addr.ip; + mr->range->max_ip = range.max_addr.ip; + /* fall through */ + case O_TO_PORTS: + mr->range->min = range.min_proto; + mr->range->max = range.max_proto; + /* fall through */ + case O_PERSISTENT: + case O_RANDOM: + case O_RANDOM_FULLY: + mr->range->flags |= range.flags; + break; + } +} + +static void NAT_parse6(struct xt_option_call *cb) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data); + struct nf_nat_range *range_v1 = (void *)cb->data; + const struct ip6t_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); + memcpy(range_v1, &range, sizeof(*range_v1)); +} + +static void DNAT_parse_v2(struct xt_option_call *cb) +{ + const struct ipt_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ip.proto, cb->data, AF_INET); +} + +static void DNAT_parse6_v2(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); +} + +static void SNAT_fcheck(struct xt_fcheck_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + mr->rangesize = 1; +} + +static void DNAT_fcheck(struct xt_fcheck_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + mr->rangesize = 1; + + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + +static void DNAT_fcheck6(struct xt_fcheck_call *cb) +{ + struct nf_nat_range *range = (void *)cb->data; + + if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + +static char *sprint_range(const struct nf_nat_range2 *r, int family) +{ + bool brackets = family == AF_INET6 && + r->flags & NF_NAT_RANGE_PROTO_SPECIFIED; + static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3]; + + buf[0] = '\0'; + + if (r->flags & NF_NAT_RANGE_MAP_IPS) { + if (brackets) + strcat(buf, "["); + inet_ntop(family, &r->min_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) { + strcat(buf, "-"); + inet_ntop(family, &r->max_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + } + if (brackets) + strcat(buf, "]"); + } + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + sprintf(buf + strlen(buf), ":%hu", + ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + sprintf(buf + strlen(buf), "-%hu", + ntohs(r->max_proto.tcp.port)); + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + sprintf(buf + strlen(buf), "/%hu", + ntohs(r->base_proto.tcp.port)); + } + return buf; +} + +static void __NAT_print(const struct nf_nat_range2 *r, int family, + const char *rangeopt, const char *flag_pfx, + bool skip_colon) +{ + char *range_str = sprint_range(r, family); + + if (strlen(range_str)) { + if (range_str[0] == ':' && skip_colon) + range_str++; + printf(" %s%s", rangeopt, range_str); + } + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", flag_pfx); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" %srandom-fully", flag_pfx); + if (r->flags & NF_NAT_RANGE_PERSISTENT) + printf(" %spersistent", flag_pfx); +} + +static int +__NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, + int family, const char *tgt) +{ + char *range_str = sprint_range(r, family); + const char *sep = " "; + + /* shifted portmap ranges are not supported by nftables */ + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + return 0; + + xt_xlate_add(xl, tgt); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, "%srandom", sep); + sep = ","; + } + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { + xt_xlate_add(xl, "%sfully-random", sep); + sep = ","; + } + if (r->flags & NF_NAT_RANGE_PERSISTENT) { + xt_xlate_add(xl, "%spersistent", sep); + sep = ","; + } + return 1; +} + +#define PSX_GEN(name, converter, family, \ + print_rangeopt, save_rangeopt, skip_colon, xlate) \ +static void name##_print(const void *ip, const struct xt_entry_target *target, \ + int numeric) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, print_rangeopt, "", skip_colon); \ +} \ +static void name##_save(const void *ip, const struct xt_entry_target *target) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, save_rangeopt, "--", skip_colon); \ +} \ +static int name##_xlate(struct xt_xlate *xl, \ + const struct xt_xlate_tg_params *params) \ +{ \ + struct nf_nat_range2 range = converter(params->target->data); \ + \ + return __NAT_xlate(xl, &range, family, xlate); \ +} + +PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \ + AF_INET, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \ + AF_INET6, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "redir ports ", "--to-ports ", true, "redirect") + +PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "redir ports ", "--to-ports ", true, "redirect") + +PSX_GEN(SNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-source ", false, "snat") + +PSX_GEN(SNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-source ", false, "snat") + +PSX_GEN(MASQUERADE, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "masq ports: ", "--to-ports ", true, "masquerade") + +PSX_GEN(MASQUERADE6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "masq ports: ", "--to-ports ", true, "masquerade") + +static struct xtables_target nat_tg_reg[] = { + { + .name = "SNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = SNAT_help, + .x6_parse = NAT_parse, + .x6_fcheck = SNAT_fcheck, + .print = SNAT_print, + .save = SNAT_save, + .x6_options = SNAT_opts, + .xlate = SNAT_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = DNAT_help, + .print = DNAT_print, + .save = DNAT_save, + .x6_parse = NAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate, + }, + { + .name = "MASQUERADE", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = MASQUERADE_help, + .x6_parse = NAT_parse, + .x6_fcheck = SNAT_fcheck, + .print = MASQUERADE_print, + .save = MASQUERADE_save, + .x6_options = MASQUERADE_opts, + .xlate = MASQUERADE_xlate, + }, + { + .name = "MASQUERADE", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = MASQUERADE_help, + .x6_parse = NAT_parse6, + .print = MASQUERADE6_print, + .save = MASQUERADE6_save, + .x6_options = MASQUERADE_opts, + .xlate = MASQUERADE6_xlate, + }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = REDIRECT_help, + .print = REDIRECT_print, + .save = REDIRECT_save, + .x6_parse = NAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate, + }, + { + .name = "SNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = SNAT_help, + .x6_parse = NAT_parse6, + .print = SNAT6_print, + .save = SNAT6_save, + .x6_options = SNAT_opts, + .xlate = SNAT6_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = DNAT_help, + .print = DNAT6_print, + .save = DNAT6_save, + .x6_parse = NAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = DNAT_opts, + .xlate = DNAT6_xlate, + }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = REDIRECT_help, + .print = REDIRECT6_print, + .save = REDIRECT6_save, + .x6_parse = NAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT6_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNATv2_print, + .save = DNATv2_save, + .x6_parse = DNAT_parse_v2, + .x6_options = DNAT_opts, + .xlate = DNATv2_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNAT6v2_print, + .save = DNAT6v2_save, + .x6_parse = DNAT_parse6_v2, + .x6_options = DNAT_opts, + .xlate = DNAT6v2_xlate, + }, +}; + +void _init(void) +{ + xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg)); +} -- cgit v1.2.3 From 0d652b8b9ed45d2cfb2e246033cc074faf8aad16 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Oct 2022 10:28:09 +0200 Subject: tests: xlate-test: Cleanup file reading loop Put the actual translation test into a function to call from the loop and clean it up a bit. Preparation work for running a second test on the same data. Signed-off-by: Phil Sutter --- xlate-test.py | 67 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 03bef7e2..ee393349 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -33,6 +33,24 @@ def green(string): return colors["green"] + string + colors["end"] +def test_one_xlate(name, sourceline, expected, result): + process = Popen([ xtables_nft_multi ] + shlex.split(sourceline), stdout=PIPE, stderr=PIPE) + (output, error) = process.communicate() + if process.returncode != 0: + result.append(name + ": " + red("Error: ") + "iptables-translate failure") + result.append(error.decode("utf-8")) + return False + + translation = output.decode("utf-8").rstrip(" \n") + if translation != expected: + result.append(name + ": " + red("Fail")) + result.append(magenta("src: ") + sourceline.rstrip(" \n")) + result.append(magenta("exp: ") + expected) + result.append(magenta("res: ") + translation + "\n") + return False + + return True + def run_test(name, payload): global xtables_nft_multi test_passed = True @@ -41,37 +59,26 @@ def run_test(name, payload): line = payload.readline() while line: - if line.startswith(keywords): - sourceline = line - tests += 1 - 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") - expected = payload.readline().rstrip(" \n") - next_expected = payload.readline() - if next_expected.startswith("nft"): - expected += "\n" + next_expected.rstrip(" \n") - line = payload.readline() - else: - line = next_expected - if translation != expected: - test_passed = False - failed += 1 - result.append(name + ": " + red("Fail")) - result.append(magenta("src: ") + sourceline.rstrip(" \n")) - result.append(magenta("exp: ") + expected) - result.append(magenta("res: ") + translation + "\n") - else: - passed += 1 - else: - test_passed = False - errors += 1 - result.append(name + ": " + red("Error: ") + "iptables-translate failure") - result.append(error.decode("utf-8")) - line = payload.readline() + if not line.startswith(keywords): + line = payload.readline() + continue + + sourceline = line + expected = payload.readline().rstrip(" \n") + next_expected = payload.readline() + if next_expected.startswith("nft"): + expected += "\n" + next_expected.rstrip(" \n") + line = payload.readline() + else: + line = next_expected + + tests += 1 + if test_one_xlate(name, sourceline, expected, result): + passed += 1 else: - line = payload.readline() + errors += 1 + test_passed = False + if (passed == tests) and not args.test: print(name + ": " + green("OK")) if not test_passed: -- cgit v1.2.3 From 595cad95fd2f61c6bc71e521ab58556f13648c30 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Oct 2022 19:07:14 +0200 Subject: tests: xlate-test.py: Introduce run_proc() It's just a convenience wrapper around Popen(), simplifying the call. Signed-off-by: Phil Sutter --- xlate-test.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index ee393349..bfcddde0 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -7,6 +7,13 @@ import shlex import argparse from subprocess import Popen, PIPE +def run_proc(args, shell = False): + """A simple wrapper around Popen, returning (rc, stdout, stderr)""" + process = Popen(args, text = True, shell = shell, + stdout = PIPE, stderr = PIPE) + output, error = process.communicate() + return (process.returncode, output, error) + keywords = ("iptables-translate", "ip6tables-translate", "ebtables-translate") xtables_nft_multi = 'xtables-nft-multi' @@ -34,14 +41,13 @@ def green(string): def test_one_xlate(name, sourceline, expected, result): - process = Popen([ xtables_nft_multi ] + shlex.split(sourceline), stdout=PIPE, stderr=PIPE) - (output, error) = process.communicate() - if process.returncode != 0: + rc, output, error = run_proc([xtables_nft_multi] + shlex.split(sourceline)) + if rc != 0: result.append(name + ": " + red("Error: ") + "iptables-translate failure") - result.append(error.decode("utf-8")) + result.append(error) return False - translation = output.decode("utf-8").rstrip(" \n") + translation = output.rstrip(" \n") if translation != expected: result.append(name + ": " + red("Fail")) result.append(magenta("src: ") + sourceline.rstrip(" \n")) -- cgit v1.2.3 From 223e34b057b95604f07c53e984b199c56140e309 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Oct 2022 12:15:21 +0200 Subject: tests: xlate-test: Replay results for reverse direction testing Call nft with translation output as input, then check xtables-save output to make sure iptables-nft can handle anything it suggests nft to turn its ruleset into. This extends the test case syntax to cover for expected asymmetries. When the existing syntax was something like this: | | | [ The new syntax then is: | [;] | | [] To keep things terse, may omit the obligatory '-A ' argument. If missing, is sanitized for how it would appear in xtables-save output: '-I' is converted into '-A' and an optional table spec is removed. Since replay mode has to manipulate the ruleset in-kernel, abort if called by unprivileged user. Also try to run in own net namespace to reduce collateral damage. Signed-off-by: Phil Sutter --- xlate-test.py | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/xlate-test.py b/xlate-test.py index bfcddde0..f3fcd797 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -57,8 +57,92 @@ def test_one_xlate(name, sourceline, expected, result): return True +def test_one_replay(name, sourceline, expected, result): + global args + + searchline = None + if sourceline.find(';') >= 0: + sourceline, searchline = sourceline.split(';') + + srcwords = sourceline.split() + + srccmd = srcwords[0] + table_idx = -1 + chain_idx = -1 + table_name = "filter" + chain_name = None + for idx in range(1, len(srcwords)): + if srcwords[idx] in ["-A", "-I", "--append", "--insert"]: + chain_idx = idx + chain_name = srcwords[idx + 1] + elif srcwords[idx] in ["-t", "--table"]: + table_idx = idx + table_name = srcwords[idx + 1] + + if not chain_name: + return True # nothing to do? + + if searchline is None: + # adjust sourceline as required + srcwords[chain_idx] = "-A" + if table_idx >= 0: + srcwords.pop(table_idx) + srcwords.pop(table_idx) + searchline = " ".join(srcwords[1:]) + elif not searchline.startswith("-A"): + tmp = ["-A", chain_name] + if len(searchline) > 0: + tmp.extend(searchline) + searchline = " ".join(tmp) + + fam = "" + if srccmd.startswith("ip6"): + fam = "ip6 " + elif srccmd.startswith("ebt"): + fam = "bridge " + nft_input = [ + "flush ruleset", + "add table " + fam + table_name, + "add chain " + fam + table_name + " " + chain_name + ] + [ l.removeprefix("nft ") for l in expected.split("\n") ] + + # feed input via the pipe to make sure the shell "does its thing" + cmd = "echo \"" + "\n".join(nft_input) + "\" | " + args.nft + " -f -" + rc, output, error = run_proc(cmd, shell = True) + if rc != 0: + result.append(name + ": " + red("Fail")) + result.append(args.nft + " call failed: " + error.rstrip('\n')) + for line in nft_input: + result.append(magenta("input: ") + line) + return False + + ipt = srccmd.split('-')[0] + rc, output, error = run_proc([xtables_nft_multi, ipt + "-save"]) + if rc != 0: + result.append(name + ": " + red("Fail")) + result.append(ipt + "-save call failed: " + error) + return False + + if output.find(searchline) < 0: + outline = None + for l in output.split('\n'): + if l.startswith('-A '): + output = l + break + result.append(name + ": " + red("Replay fail")) + result.append(magenta("src: '") + expected + "'") + result.append(magenta("exp: '") + searchline + "'") + for l in output.split('\n'): + result.append(magenta("res: ") + l) + return False + + return True + + def run_test(name, payload): global xtables_nft_multi + global args + test_passed = True tests = passed = failed = errors = 0 result = [] @@ -69,7 +153,10 @@ def run_test(name, payload): line = payload.readline() continue - sourceline = line + sourceline = replayline = line.rstrip("\n") + if line.find(';') >= 0: + sourceline = line.split(';')[0] + expected = payload.readline().rstrip(" \n") next_expected = payload.readline() if next_expected.startswith("nft"): @@ -84,6 +171,20 @@ def run_test(name, payload): else: errors += 1 test_passed = False + continue + + if args.replay: + tests += 1 + if test_one_replay(name, replayline, expected, result): + passed += 1 + else: + errors += 1 + test_passed = False + + rc, output, error = run_proc([args.nft, "flush", "ruleset"]) + if rc != 0: + result.append(name + ": " + red("Fail")) + result.append("nft flush ruleset call failed: " + error) if (passed == tests) and not args.test: print(name + ": " + green("OK")) @@ -106,8 +207,44 @@ def load_test_files(): return (test_files, total_tests, total_passed, total_failed, total_error) +def spawn_netns(): + # prefer unshare module + try: + import unshare + unshare.unshare(unshare.CLONE_NEWNET) + return True + except: + pass + + # sledgehammer style: + # - call ourselves prefixed by 'unshare -n' if found + # - pass extra --no-netns parameter to avoid another recursion + try: + import shutil + + unshare = shutil.which("unshare") + if unshare is None: + return False + + sys.argv.append("--no-netns") + os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv) + except: + pass + + return False + + def main(): global xtables_nft_multi + + if args.replay: + if os.getuid() != 0: + print("Replay test requires root, sorry", file=sys.stderr) + return + if not args.no_netns and not spawn_netns(): + print("Cannot run in own namespace, connectivity might break", + file=sys.stderr) + if not args.host: os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions")) xtables_nft_multi = os.path.abspath(os.path.curdir) \ @@ -139,6 +276,12 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('-H', '--host', action='store_true', help='Run tests against installed binaries') +parser.add_argument('-R', '--replay', action='store_true', + help='Replay tests to check iptables-nft parser') +parser.add_argument('-n', '--nft', type=str, default='nft', + help='Replay using given nft binary (default: \'%(default)s\')') +parser.add_argument('--no-netns', action='store_true', + help='Do not run testsuite in own network namespace') parser.add_argument("test", nargs="?", help="run only the specified test file") args = parser.parse_args() sys.exit(main()) -- cgit v1.2.3 From eb2546a8467764de357598e6a54ddbc23ca5ee7d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 12 May 2020 18:46:39 +0200 Subject: xshared: Share make_delete_mask() between ip{,6}tables Function bodies were mostly identical, the only difference being the use of struct ipt_entry or ip6t_entry for size calculation. Pass this value via parameter to make them fully identical. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 38 ++------------------------------------ iptables/iptables.c | 38 ++------------------------------------ iptables/xshared.c | 34 ++++++++++++++++++++++++++++++++++ iptables/xshared.h | 4 ++++ 4 files changed, 42 insertions(+), 72 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 75984cc1..ae267035 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -277,40 +277,6 @@ insert_entry(const xt_chainlabel chain, return ret; } -static unsigned char * -make_delete_mask(const struct xtables_rule_match *matches, - const struct xtables_target *target) -{ - /* Establish mask for comparison */ - unsigned int size; - const struct xtables_rule_match *matchp; - unsigned char *mask, *mptr; - - size = sizeof(struct ip6t_entry); - for (matchp = matches; matchp; matchp = matchp->next) - size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - - mask = xtables_calloc(1, size - + XT_ALIGN(sizeof(struct xt_entry_target)) - + target->size); - - memset(mask, 0xFF, sizeof(struct ip6t_entry)); - mptr = mask + sizeof(struct ip6t_entry); - - for (matchp = matches; matchp; matchp = matchp->next) { - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_match)) - + matchp->match->userspacesize); - mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - } - - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_target)) - + target->userspacesize); - - return mask; -} - static int delete_entry(const xt_chainlabel chain, struct ip6t_entry *fw, @@ -329,7 +295,7 @@ delete_entry(const xt_chainlabel chain, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; fw->ipv6.smsk = smasks[i]; @@ -359,7 +325,7 @@ check_entry(const xt_chainlabel chain, struct ip6t_entry *fw, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(fw)); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; fw->ipv6.smsk = smasks[i]; diff --git a/iptables/iptables.c b/iptables/iptables.c index e5207ba1..591ec178 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -276,40 +276,6 @@ insert_entry(const xt_chainlabel chain, return ret; } -static unsigned char * -make_delete_mask(const struct xtables_rule_match *matches, - const struct xtables_target *target) -{ - /* Establish mask for comparison */ - unsigned int size; - const struct xtables_rule_match *matchp; - unsigned char *mask, *mptr; - - size = sizeof(struct ipt_entry); - for (matchp = matches; matchp; matchp = matchp->next) - size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - - mask = xtables_calloc(1, size - + XT_ALIGN(sizeof(struct xt_entry_target)) - + target->size); - - memset(mask, 0xFF, sizeof(struct ipt_entry)); - mptr = mask + sizeof(struct ipt_entry); - - for (matchp = matches; matchp; matchp = matchp->next) { - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_match)) - + matchp->match->userspacesize); - mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - } - - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_target)) - + target->userspacesize); - - return mask; -} - static int delete_entry(const xt_chainlabel chain, struct ipt_entry *fw, @@ -328,7 +294,7 @@ delete_entry(const xt_chainlabel chain, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ip.src.s_addr = saddrs[i].s_addr; fw->ip.smsk.s_addr = smasks[i].s_addr; @@ -358,7 +324,7 @@ check_entry(const xt_chainlabel chain, struct ipt_entry *fw, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ip.src.s_addr = saddrs[i].s_addr; fw->ip.smsk.s_addr = smasks[i].s_addr; diff --git a/iptables/xshared.c b/iptables/xshared.c index 69515789..0beacee6 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -2000,3 +2000,37 @@ void ipv6_post_parse(int command, struct iptables_command_state *cs, "! not allowed with multiple" " source or destination IP addresses"); } + +unsigned char * +make_delete_mask(const struct xtables_rule_match *matches, + const struct xtables_target *target, + size_t entry_size) +{ + /* Establish mask for comparison */ + unsigned int size = entry_size; + const struct xtables_rule_match *matchp; + unsigned char *mask, *mptr; + + for (matchp = matches; matchp; matchp = matchp->next) + size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; + + mask = xtables_calloc(1, size + + XT_ALIGN(sizeof(struct xt_entry_target)) + + target->size); + + memset(mask, 0xFF, entry_size); + mptr = mask + entry_size; + + for (matchp = matches; matchp; matchp = matchp->next) { + memset(mptr, 0xFF, + XT_ALIGN(sizeof(struct xt_entry_match)) + + matchp->match->userspacesize); + mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; + } + + memset(mptr, 0xFF, + XT_ALIGN(sizeof(struct xt_entry_target)) + + target->userspacesize); + + return mask; +} diff --git a/iptables/xshared.h b/iptables/xshared.h index f43c28f5..bfae4b4e 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -293,4 +293,8 @@ void ipv6_post_parse(int command, struct iptables_command_state *cs, extern char *arp_opcodes[]; #define ARP_NUMOPCODES 9 +unsigned char *make_delete_mask(const struct xtables_rule_match *matches, + const struct xtables_target *target, + size_t entry_size); + #endif /* IPTABLES_XSHARED_H */ -- cgit v1.2.3 From d9813e31f7e616b2e0dfea841aecfe40dd51a697 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 6 Oct 2022 18:20:14 +0200 Subject: nft-shared: Introduce port_match_single_to_range() The same algorithm was present four times, outsource it. Also use max()/min() macros for a more readable boundary notation. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 130 ++++++++++++++------------------------------------ 1 file changed, 37 insertions(+), 93 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 996cff99..e5e3ac0b 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -747,6 +747,35 @@ static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, } } +static void port_match_single_to_range(__u16 *ports, __u8 *invflags, + uint8_t op, int port, __u8 invflag) +{ + if (port < 0) + return; + + switch (op) { + case NFT_CMP_NEQ: + *invflags |= invflag; + /* fallthrough */ + case NFT_CMP_EQ: + ports[0] = port; + ports[1] = port; + break; + case NFT_CMP_LT: + ports[1] = max(port - 1, 1); + break; + case NFT_CMP_LTE: + ports[1] = port; + break; + case NFT_CMP_GT: + ports[0] = min(port + 1, UINT16_MAX); + break; + case NFT_CMP_GTE: + ports[0] = port; + break; + } +} + static void nft_parse_udp(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, int sport, int dport, @@ -757,52 +786,10 @@ static void nft_parse_udp(struct nft_xt_ctx *ctx, if (!udp) return; - if (sport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_SRCPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->spts[0] = sport; - udp->spts[1] = sport; - break; - case NFT_CMP_LT: - udp->spts[1] = sport > 1 ? sport - 1 : 1; - break; - case NFT_CMP_LTE: - udp->spts[1] = sport; - break; - case NFT_CMP_GT: - udp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - udp->spts[0] = sport; - break; - } - } - if (dport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->dpts[0] = dport; - udp->dpts[1] = dport; - break; - case NFT_CMP_LT: - udp->dpts[1] = dport > 1 ? dport - 1 : 1; - break; - case NFT_CMP_LTE: - udp->dpts[1] = dport; - break; - case NFT_CMP_GT: - udp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - udp->dpts[0] = dport; - break; - } - } + port_match_single_to_range(udp->spts, &udp->invflags, + op, sport, XT_UDP_INV_SRCPT); + port_match_single_to_range(udp->dpts, &udp->invflags, + op, dport, XT_UDP_INV_DSTPT); } static void nft_parse_tcp(struct nft_xt_ctx *ctx, @@ -815,53 +802,10 @@ static void nft_parse_tcp(struct nft_xt_ctx *ctx, if (!tcp) return; - if (sport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_SRCPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->spts[0] = sport; - tcp->spts[1] = sport; - break; - case NFT_CMP_LT: - tcp->spts[1] = sport > 1 ? sport - 1 : 1; - break; - case NFT_CMP_LTE: - tcp->spts[1] = sport; - break; - case NFT_CMP_GT: - tcp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - tcp->spts[0] = sport; - break; - } - } - - if (dport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->dpts[0] = dport; - tcp->dpts[1] = dport; - break; - case NFT_CMP_LT: - tcp->dpts[1] = dport > 1 ? dport - 1 : 1; - break; - case NFT_CMP_LTE: - tcp->dpts[1] = dport; - break; - case NFT_CMP_GT: - tcp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - tcp->dpts[0] = dport; - break; - } - } + port_match_single_to_range(tcp->spts, &tcp->invflags, + op, sport, XT_TCP_INV_SRCPT); + port_match_single_to_range(tcp->dpts, &tcp->invflags, + op, dport, XT_TCP_INV_DSTPT); } static void nft_parse_th_port(struct nft_xt_ctx *ctx, -- cgit v1.2.3 From 87e4f1bf0b87b23f0fe29e5f9976d64843de8785 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 22 Oct 2022 15:16:59 +0200 Subject: extensions: libip*t_LOG: Merge extensions Data structures were identical already, make use of the names in xt_LOG.h and merge all code into a single extension of family NFPROTO_UNSPEC. While being at it, define SYSLOG_NAMES and use the array in syslog.h instead of dragging along an own level->name mapping two times. Signed-off-by: Phil Sutter --- extensions/libip6t_LOG.c | 250 ----------------------------------------------- extensions/libipt_LOG.c | 250 ----------------------------------------------- extensions/libxt_LOG.c | 208 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 500 deletions(-) delete mode 100644 extensions/libip6t_LOG.c delete mode 100644 extensions/libipt_LOG.c create mode 100644 extensions/libxt_LOG.c diff --git a/extensions/libip6t_LOG.c b/extensions/libip6t_LOG.c deleted file mode 100644 index 40adc69d..00000000 --- a/extensions/libip6t_LOG.c +++ /dev/null @@ -1,250 +0,0 @@ -#include -#include -#include -#include -#include - -#ifndef IP6T_LOG_UID /* Old kernel */ -#define IP6T_LOG_UID 0x08 -#undef IP6T_LOG_MASK -#define IP6T_LOG_MASK 0x0f -#endif - -#define LOG_DEFAULT_LEVEL LOG_WARNING - -enum { - O_LOG_LEVEL = 0, - O_LOG_PREFIX, - O_LOG_TCPSEQ, - O_LOG_TCPOPTS, - O_LOG_IPOPTS, - O_LOG_UID, - O_LOG_MAC, -}; - -static void LOG_help(void) -{ - printf( -"LOG target options:\n" -" --log-level level Level of logging (numeric or see syslog.conf)\n" -" --log-prefix prefix Prefix log messages with this prefix.\n" -" --log-tcp-sequence Log TCP sequence numbers.\n" -" --log-tcp-options Log TCP options.\n" -" --log-ip-options Log IP options.\n" -" --log-uid Log UID owning the local socket.\n" -" --log-macdecode Decode MAC addresses and protocol.\n"); -} - -#define s struct ip6t_log_info -static const struct xt_option_entry LOG_opts[] = { - {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, - .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, - {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, - .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, - {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, - {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, - {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, - {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, - {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; -#undef s - -static void LOG_init(struct xt_entry_target *t) -{ - struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data; - - loginfo->level = LOG_DEFAULT_LEVEL; - -} - -struct ip6t_log_names { - const char *name; - unsigned int level; -}; - -struct ip6t_log_xlate { - const char *name; - unsigned int level; -}; - -static const struct ip6t_log_names ip6t_log_names[] -= { { .name = "alert", .level = LOG_ALERT }, - { .name = "crit", .level = LOG_CRIT }, - { .name = "debug", .level = LOG_DEBUG }, - { .name = "emerg", .level = LOG_EMERG }, - { .name = "error", .level = LOG_ERR }, /* DEPRECATED */ - { .name = "info", .level = LOG_INFO }, - { .name = "notice", .level = LOG_NOTICE }, - { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */ - { .name = "warning", .level = LOG_WARNING } -}; - -static void LOG_parse(struct xt_option_call *cb) -{ - struct ip6t_log_info *info = cb->data; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_LOG_PREFIX: - if (strchr(cb->arg, '\n') != NULL) - xtables_error(PARAMETER_PROBLEM, - "Newlines not allowed in --log-prefix"); - break; - case O_LOG_TCPSEQ: - info->logflags |= IP6T_LOG_TCPSEQ; - break; - case O_LOG_TCPOPTS: - info->logflags |= IP6T_LOG_TCPOPT; - break; - case O_LOG_IPOPTS: - info->logflags |= IP6T_LOG_IPOPT; - break; - case O_LOG_UID: - info->logflags |= IP6T_LOG_UID; - break; - case O_LOG_MAC: - info->logflags |= IP6T_LOG_MACDECODE; - break; - } -} - -static void LOG_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ip6t_log_info *loginfo - = (const struct ip6t_log_info *)target->data; - unsigned int i = 0; - - printf(" LOG"); - if (numeric) - printf(" flags %u level %u", - loginfo->logflags, loginfo->level); - else { - for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i) - if (loginfo->level == ip6t_log_names[i].level) { - printf(" level %s", ip6t_log_names[i].name); - break; - } - if (i == ARRAY_SIZE(ip6t_log_names)) - printf(" UNKNOWN level %u", loginfo->level); - if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf(" tcp-sequence"); - if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf(" tcp-options"); - if (loginfo->logflags & IP6T_LOG_IPOPT) - printf(" ip-options"); - if (loginfo->logflags & IP6T_LOG_UID) - printf(" uid"); - if (loginfo->logflags & IP6T_LOG_MACDECODE) - printf(" macdecode"); - if (loginfo->logflags & ~(IP6T_LOG_MASK)) - printf(" unknown-flags"); - } - - if (strcmp(loginfo->prefix, "") != 0) - printf(" prefix \"%s\"", loginfo->prefix); -} - -static void LOG_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ip6t_log_info *loginfo - = (const struct ip6t_log_info *)target->data; - - if (strcmp(loginfo->prefix, "") != 0) { - printf(" --log-prefix"); - xtables_save_string(loginfo->prefix); - } - - if (loginfo->level != LOG_DEFAULT_LEVEL) - printf(" --log-level %d", loginfo->level); - - if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf(" --log-tcp-sequence"); - if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf(" --log-tcp-options"); - if (loginfo->logflags & IP6T_LOG_IPOPT) - printf(" --log-ip-options"); - if (loginfo->logflags & IP6T_LOG_UID) - printf(" --log-uid"); - if (loginfo->logflags & IP6T_LOG_MACDECODE) - printf(" --log-macdecode"); -} - -static const struct ip6t_log_xlate ip6t_log_xlate_names[] = { - {"alert", LOG_ALERT }, - {"crit", LOG_CRIT }, - {"debug", LOG_DEBUG }, - {"emerg", LOG_EMERG }, - {"err", LOG_ERR }, - {"info", LOG_INFO }, - {"notice", LOG_NOTICE }, - {"warn", LOG_WARNING } -}; - -static int LOG_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct ip6t_log_info *loginfo = - (const struct ip6t_log_info *)params->target->data; - unsigned int i = 0; - - xt_xlate_add(xl, "log"); - if (strcmp(loginfo->prefix, "") != 0) { - if (params->escape_quotes) - xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); - else - xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); - } - - for (i = 0; i < ARRAY_SIZE(ip6t_log_xlate_names); ++i) - if (loginfo->level == ip6t_log_xlate_names[i].level && - loginfo->level != LOG_DEFAULT_LEVEL) { - xt_xlate_add(xl, " level %s", - ip6t_log_xlate_names[i].name); - break; - } - - if ((loginfo->logflags & IP6T_LOG_MASK) == IP6T_LOG_MASK) { - xt_xlate_add(xl, " flags all"); - } else { - if (loginfo->logflags & (IP6T_LOG_TCPSEQ | IP6T_LOG_TCPOPT)) { - const char *delim = " "; - - xt_xlate_add(xl, " flags tcp"); - if (loginfo->logflags & IP6T_LOG_TCPSEQ) { - xt_xlate_add(xl, " sequence"); - delim = ","; - } - if (loginfo->logflags & IP6T_LOG_TCPOPT) - xt_xlate_add(xl, "%soptions", delim); - } - if (loginfo->logflags & IP6T_LOG_IPOPT) - xt_xlate_add(xl, " flags ip options"); - if (loginfo->logflags & IP6T_LOG_UID) - xt_xlate_add(xl, " flags skuid"); - if (loginfo->logflags & IP6T_LOG_MACDECODE) - xt_xlate_add(xl, " flags ether"); - } - - return 1; -} -static struct xtables_target log_tg6_reg = { - .name = "LOG", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct ip6t_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)), - .help = LOG_help, - .init = LOG_init, - .print = LOG_print, - .save = LOG_save, - .x6_parse = LOG_parse, - .x6_options = LOG_opts, - .xlate = LOG_xlate, -}; - -void _init(void) -{ - xtables_register_target(&log_tg6_reg); -} diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c deleted file mode 100644 index 36e2e73b..00000000 --- a/extensions/libipt_LOG.c +++ /dev/null @@ -1,250 +0,0 @@ -#include -#include -#include -#include -#include - -#define LOG_DEFAULT_LEVEL LOG_WARNING - -#ifndef IPT_LOG_UID /* Old kernel */ -#define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#undef IPT_LOG_MASK -#define IPT_LOG_MASK 0x0f -#endif - -enum { - O_LOG_LEVEL = 0, - O_LOG_PREFIX, - O_LOG_TCPSEQ, - O_LOG_TCPOPTS, - O_LOG_IPOPTS, - O_LOG_UID, - O_LOG_MAC, -}; - -static void LOG_help(void) -{ - printf( -"LOG target options:\n" -" --log-level level Level of logging (numeric or see syslog.conf)\n" -" --log-prefix prefix Prefix log messages with this prefix.\n\n" -" --log-tcp-sequence Log TCP sequence numbers.\n\n" -" --log-tcp-options Log TCP options.\n\n" -" --log-ip-options Log IP options.\n\n" -" --log-uid Log UID owning the local socket.\n\n" -" --log-macdecode Decode MAC addresses and protocol.\n\n"); -} - -#define s struct ipt_log_info -static const struct xt_option_entry LOG_opts[] = { - {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, - .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, - {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, - .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, - {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, - {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, - {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, - {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, - {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; -#undef s - -static void LOG_init(struct xt_entry_target *t) -{ - struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data; - - loginfo->level = LOG_DEFAULT_LEVEL; - -} - -struct ipt_log_names { - const char *name; - unsigned int level; -}; - -struct ipt_log_xlate { - const char *name; - unsigned int level; -}; - -static const struct ipt_log_names ipt_log_names[] -= { { .name = "alert", .level = LOG_ALERT }, - { .name = "crit", .level = LOG_CRIT }, - { .name = "debug", .level = LOG_DEBUG }, - { .name = "emerg", .level = LOG_EMERG }, - { .name = "error", .level = LOG_ERR }, /* DEPRECATED */ - { .name = "info", .level = LOG_INFO }, - { .name = "notice", .level = LOG_NOTICE }, - { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */ - { .name = "warning", .level = LOG_WARNING } -}; - -static void LOG_parse(struct xt_option_call *cb) -{ - struct ipt_log_info *info = cb->data; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_LOG_PREFIX: - if (strchr(cb->arg, '\n') != NULL) - xtables_error(PARAMETER_PROBLEM, - "Newlines not allowed in --log-prefix"); - break; - case O_LOG_TCPSEQ: - info->logflags |= IPT_LOG_TCPSEQ; - break; - case O_LOG_TCPOPTS: - info->logflags |= IPT_LOG_TCPOPT; - break; - case O_LOG_IPOPTS: - info->logflags |= IPT_LOG_IPOPT; - break; - case O_LOG_UID: - info->logflags |= IPT_LOG_UID; - break; - case O_LOG_MAC: - info->logflags |= IPT_LOG_MACDECODE; - break; - } -} - -static void LOG_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ipt_log_info *loginfo - = (const struct ipt_log_info *)target->data; - unsigned int i = 0; - - printf(" LOG"); - if (numeric) - printf(" flags %u level %u", - loginfo->logflags, loginfo->level); - else { - for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) - if (loginfo->level == ipt_log_names[i].level) { - printf(" level %s", ipt_log_names[i].name); - break; - } - if (i == ARRAY_SIZE(ipt_log_names)) - printf(" UNKNOWN level %u", loginfo->level); - if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf(" tcp-sequence"); - if (loginfo->logflags & IPT_LOG_TCPOPT) - printf(" tcp-options"); - if (loginfo->logflags & IPT_LOG_IPOPT) - printf(" ip-options"); - if (loginfo->logflags & IPT_LOG_UID) - printf(" uid"); - if (loginfo->logflags & IPT_LOG_MACDECODE) - printf(" macdecode"); - if (loginfo->logflags & ~(IPT_LOG_MASK)) - printf(" unknown-flags"); - } - - if (strcmp(loginfo->prefix, "") != 0) - printf(" prefix \"%s\"", loginfo->prefix); -} - -static void LOG_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ipt_log_info *loginfo - = (const struct ipt_log_info *)target->data; - - if (strcmp(loginfo->prefix, "") != 0) { - printf(" --log-prefix"); - xtables_save_string(loginfo->prefix); - } - - if (loginfo->level != LOG_DEFAULT_LEVEL) - printf(" --log-level %d", loginfo->level); - - if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf(" --log-tcp-sequence"); - if (loginfo->logflags & IPT_LOG_TCPOPT) - printf(" --log-tcp-options"); - if (loginfo->logflags & IPT_LOG_IPOPT) - printf(" --log-ip-options"); - if (loginfo->logflags & IPT_LOG_UID) - printf(" --log-uid"); - if (loginfo->logflags & IPT_LOG_MACDECODE) - printf(" --log-macdecode"); -} - -static const struct ipt_log_xlate ipt_log_xlate_names[] = { - {"alert", LOG_ALERT }, - {"crit", LOG_CRIT }, - {"debug", LOG_DEBUG }, - {"emerg", LOG_EMERG }, - {"err", LOG_ERR }, - {"info", LOG_INFO }, - {"notice", LOG_NOTICE }, - {"warn", LOG_WARNING } -}; - -static int LOG_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct ipt_log_info *loginfo = - (const struct ipt_log_info *)params->target->data; - unsigned int i = 0; - - xt_xlate_add(xl, "log"); - if (strcmp(loginfo->prefix, "") != 0) { - if (params->escape_quotes) - xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); - else - xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); - } - - for (i = 0; i < ARRAY_SIZE(ipt_log_xlate_names); ++i) - if (loginfo->level != LOG_DEFAULT_LEVEL && - loginfo->level == ipt_log_xlate_names[i].level) { - xt_xlate_add(xl, " level %s", - ipt_log_xlate_names[i].name); - break; - } - - if ((loginfo->logflags & IPT_LOG_MASK) == IPT_LOG_MASK) { - xt_xlate_add(xl, " flags all"); - } else { - if (loginfo->logflags & (IPT_LOG_TCPSEQ | IPT_LOG_TCPOPT)) { - const char *delim = " "; - - xt_xlate_add(xl, " flags tcp"); - if (loginfo->logflags & IPT_LOG_TCPSEQ) { - xt_xlate_add(xl, " sequence"); - delim = ","; - } - if (loginfo->logflags & IPT_LOG_TCPOPT) - xt_xlate_add(xl, "%soptions", delim); - } - if (loginfo->logflags & IPT_LOG_IPOPT) - xt_xlate_add(xl, " flags ip options"); - if (loginfo->logflags & IPT_LOG_UID) - xt_xlate_add(xl, " flags skuid"); - if (loginfo->logflags & IPT_LOG_MACDECODE) - xt_xlate_add(xl, " flags ether"); - } - - return 1; -} -static struct xtables_target log_tg_reg = { - .name = "LOG", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)), - .help = LOG_help, - .init = LOG_init, - .print = LOG_print, - .save = LOG_save, - .x6_parse = LOG_parse, - .x6_options = LOG_opts, - .xlate = LOG_xlate, -}; - -void _init(void) -{ - xtables_register_target(&log_tg_reg); -} diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c new file mode 100644 index 00000000..e3f4290b --- /dev/null +++ b/extensions/libxt_LOG.c @@ -0,0 +1,208 @@ +#include +#include +#define SYSLOG_NAMES +#include +#include +#include + +#define LOG_DEFAULT_LEVEL LOG_WARNING + +enum { + /* make sure the values correspond with XT_LOG_* bit positions */ + O_LOG_TCPSEQ = 0, + O_LOG_TCPOPTS, + O_LOG_IPOPTS, + O_LOG_UID, + __O_LOG_NFLOG, + O_LOG_MAC, + O_LOG_LEVEL, + O_LOG_PREFIX, +}; + +static void LOG_help(void) +{ + printf( +"LOG target options:\n" +" --log-level level Level of logging (numeric or see syslog.conf)\n" +" --log-prefix prefix Prefix log messages with this prefix.\n" +" --log-tcp-sequence Log TCP sequence numbers.\n" +" --log-tcp-options Log TCP options.\n" +" --log-ip-options Log IP options.\n" +" --log-uid Log UID owning the local socket.\n" +" --log-macdecode Decode MAC addresses and protocol.\n"); +} + +#define s struct xt_log_info +static const struct xt_option_entry LOG_opts[] = { + {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, + .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, + {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, + {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, + {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, + {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, + {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, + {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; +#undef s + +static void LOG_init(struct xt_entry_target *t) +{ + struct xt_log_info *loginfo = (void *)t->data; + + loginfo->level = LOG_DEFAULT_LEVEL; +} + +static void LOG_parse(struct xt_option_call *cb) +{ + struct xt_log_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LOG_PREFIX: + if (strchr(cb->arg, '\n') != NULL) + xtables_error(PARAMETER_PROBLEM, + "Newlines not allowed in --log-prefix"); + break; + case O_LOG_TCPSEQ: + case O_LOG_TCPOPTS: + case O_LOG_IPOPTS: + case O_LOG_UID: + case O_LOG_MAC: + info->logflags |= 1 << cb->entry->id; + break; + } +} + +static const char *priority2name(unsigned char level) +{ + int i; + + for (i = 0; prioritynames[i].c_name; ++i) { + if (level == prioritynames[i].c_val) + return prioritynames[i].c_name; + } + return NULL; +} + +static void LOG_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_log_info *loginfo = (const void *)target->data; + + printf(" LOG"); + if (numeric) + printf(" flags %u level %u", + loginfo->logflags, loginfo->level); + else { + const char *pname = priority2name(loginfo->level); + + if (pname) + printf(" level %s", pname); + else + printf(" UNKNOWN level %u", loginfo->level); + if (loginfo->logflags & XT_LOG_TCPSEQ) + printf(" tcp-sequence"); + if (loginfo->logflags & XT_LOG_TCPOPT) + printf(" tcp-options"); + if (loginfo->logflags & XT_LOG_IPOPT) + printf(" ip-options"); + if (loginfo->logflags & XT_LOG_UID) + printf(" uid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + printf(" macdecode"); + if (loginfo->logflags & ~(XT_LOG_MASK)) + printf(" unknown-flags"); + } + + if (strcmp(loginfo->prefix, "") != 0) + printf(" prefix \"%s\"", loginfo->prefix); +} + +static void LOG_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_log_info *loginfo = (const void *)target->data; + + if (strcmp(loginfo->prefix, "") != 0) { + printf(" --log-prefix"); + xtables_save_string(loginfo->prefix); + } + + if (loginfo->level != LOG_DEFAULT_LEVEL) + printf(" --log-level %d", loginfo->level); + + if (loginfo->logflags & XT_LOG_TCPSEQ) + printf(" --log-tcp-sequence"); + if (loginfo->logflags & XT_LOG_TCPOPT) + printf(" --log-tcp-options"); + if (loginfo->logflags & XT_LOG_IPOPT) + printf(" --log-ip-options"); + if (loginfo->logflags & XT_LOG_UID) + printf(" --log-uid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + printf(" --log-macdecode"); +} + +static int LOG_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct xt_log_info *loginfo = (const void *)params->target->data; + const char *pname = priority2name(loginfo->level); + + xt_xlate_add(xl, "log"); + if (strcmp(loginfo->prefix, "") != 0) { + if (params->escape_quotes) + xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); + else + xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); + } + + if (loginfo->level != LOG_DEFAULT_LEVEL && pname) + xt_xlate_add(xl, " level %s", pname); + else if (!pname) + return 0; + + if ((loginfo->logflags & XT_LOG_MASK) == XT_LOG_MASK) { + xt_xlate_add(xl, " flags all"); + } else { + if (loginfo->logflags & (XT_LOG_TCPSEQ | XT_LOG_TCPOPT)) { + const char *delim = " "; + + xt_xlate_add(xl, " flags tcp"); + if (loginfo->logflags & XT_LOG_TCPSEQ) { + xt_xlate_add(xl, " sequence"); + delim = ","; + } + if (loginfo->logflags & XT_LOG_TCPOPT) + xt_xlate_add(xl, "%soptions", delim); + } + if (loginfo->logflags & XT_LOG_IPOPT) + xt_xlate_add(xl, " flags ip options"); + if (loginfo->logflags & XT_LOG_UID) + xt_xlate_add(xl, " flags skuid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + xt_xlate_add(xl, " flags ether"); + } + + return 1; +} +static struct xtables_target log_tg_reg = { + .name = "LOG", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_log_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_log_info)), + .help = LOG_help, + .init = LOG_init, + .print = LOG_print, + .save = LOG_save, + .x6_parse = LOG_parse, + .x6_options = LOG_opts, + .xlate = LOG_xlate, +}; + +void _init(void) +{ + xtables_register_target(&log_tg_reg); +} -- cgit v1.2.3 From f44dd71ed81459ce549204afb2283c4dc709ab47 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 6 Oct 2022 15:09:32 +0200 Subject: extensions: libebt_ip: Include kernel header Update the local copy of linux/netfilter_bridge/ebt_ip.h and include it instead of keeping the local copy of struct ebt_ip_info et al. Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 32 +------------------------------- include/linux/netfilter_bridge/ebt_ip.h | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index 51649ffb..8413a5aa 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -20,40 +20,10 @@ #include #include #include +#include #include "libxt_icmp.h" -#define EBT_IP_SOURCE 0x01 -#define EBT_IP_DEST 0x02 -#define EBT_IP_TOS 0x04 -#define EBT_IP_PROTO 0x08 -#define EBT_IP_SPORT 0x10 -#define EBT_IP_DPORT 0x20 -#define EBT_IP_ICMP 0x40 -#define EBT_IP_IGMP 0x80 -#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ - EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP) - -struct ebt_ip_info { - __be32 saddr; - __be32 daddr; - __be32 smsk; - __be32 dmsk; - __u8 tos; - __u8 protocol; - __u8 bitmask; - __u8 invflags; - union { - __u16 sport[2]; - __u8 icmp_type[2]; - __u8 igmp_type[2]; - }; - union { - __u16 dport[2]; - __u8 icmp_code[2]; - }; -}; - #define IP_SOURCE '1' #define IP_DEST '2' #define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */ diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h index c4bbc41b..ae5d4d10 100644 --- a/include/linux/netfilter_bridge/ebt_ip.h +++ b/include/linux/netfilter_bridge/ebt_ip.h @@ -23,8 +23,10 @@ #define EBT_IP_PROTO 0x08 #define EBT_IP_SPORT 0x10 #define EBT_IP_DPORT 0x20 +#define EBT_IP_ICMP 0x40 +#define EBT_IP_IGMP 0x80 #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ - EBT_IP_SPORT | EBT_IP_DPORT ) + EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP) #define EBT_IP_MATCH "ip" /* the same values are used for the invflags */ @@ -37,8 +39,15 @@ struct ebt_ip_info { __u8 protocol; __u8 bitmask; __u8 invflags; - __u16 sport[2]; - __u16 dport[2]; + union { + __u16 sport[2]; + __u8 icmp_type[2]; + __u8 igmp_type[2]; + }; + union { + __u16 dport[2]; + __u8 icmp_code[2]; + }; }; #endif -- cgit v1.2.3 From 319f3b7f6e0e9d090cc2805c7a318bfc702fed17 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 6 Oct 2022 14:54:48 +0200 Subject: extensions: libebt_arp, libebt_ip: Use xtables_ipparse_any() The libxtables function covers all formerly supported inputs (and more). The extended libebt_arp.t passes before and after this patch. Signed-off-by: Phil Sutter --- extensions/libebt_arp.c | 89 +++++-------------------------------------------- extensions/libebt_arp.t | 3 ++ extensions/libebt_ip.c | 86 ++++++----------------------------------------- 3 files changed, 21 insertions(+), 157 deletions(-) diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c index d5035b95..63a953d4 100644 --- a/extensions/libebt_arp.c +++ b/extensions/libebt_arp.c @@ -87,91 +87,17 @@ static void brarp_print_help(void) #define OPT_MAC_D 0x40 #define OPT_GRAT 0x80 -static int undot_ip(char *ip, unsigned char *ip2) -{ - char *p, *q, *end; - long int onebyte; - int i; - char buf[20]; - - strncpy(buf, ip, sizeof(buf) - 1); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return -1; - *q = '\0'; - onebyte = strtol(p, &end, 10); - if (*end != '\0' || onebyte > 255 || onebyte < 0) - return -1; - ip2[i] = (unsigned char)onebyte; - p = q + 1; - } - - onebyte = strtol(p, &end, 10); - if (*end != '\0' || onebyte > 255 || onebyte < 0) - return -1; - ip2[3] = (unsigned char)onebyte; - - return 0; -} - -static int ip_mask(char *mask, unsigned char *mask2) -{ - char *end; - long int bits; - uint32_t mask22; - - if (undot_ip(mask, mask2)) { - /* not the /a.b.c.e format, maybe the /x format */ - bits = strtol(mask, &end, 10); - if (*end != '\0' || bits > 32 || bits < 0) - return -1; - if (bits != 0) { - mask22 = htonl(0xFFFFFFFF << (32 - bits)); - memcpy(mask2, &mask22, 4); - } else { - mask22 = 0xFFFFFFFF; - memcpy(mask2, &mask22, 4); - } - } - return 0; -} - -static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) -{ - char *p; - - /* first the mask */ - if ((p = strrchr(address, '/')) != NULL) { - *p = '\0'; - if (ip_mask(p + 1, (unsigned char *)msk)) { - xtables_error(PARAMETER_PROBLEM, - "Problem with the IP mask '%s'", p + 1); - return; - } - } else - *msk = 0xFFFFFFFF; - - if (undot_ip(address, (unsigned char *)addr)) { - xtables_error(PARAMETER_PROBLEM, - "Problem with the IP address '%s'", address); - return; - } - *addr = *addr & *msk; -} - static int brarp_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data; + struct in_addr *ipaddr, ipmask; long int i; char *end; - uint32_t *addr; - uint32_t *mask; unsigned char *maddr; unsigned char *mmask; + unsigned int ipnr; switch (c) { case ARP_OPCODE: @@ -231,24 +157,25 @@ brarp_parse(int c, char **argv, int invert, unsigned int *flags, case ARP_IP_S: case ARP_IP_D: + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); if (c == ARP_IP_S) { EBT_CHECK_OPTION(flags, OPT_IP_S); - addr = &arpinfo->saddr; - mask = &arpinfo->smsk; + arpinfo->saddr = ipaddr->s_addr; + arpinfo->smsk = ipmask.s_addr; arpinfo->bitmask |= EBT_ARP_SRC_IP; } else { EBT_CHECK_OPTION(flags, OPT_IP_D); - addr = &arpinfo->daddr; - mask = &arpinfo->dmsk; + arpinfo->daddr = ipaddr->s_addr; + arpinfo->dmsk = ipmask.s_addr; arpinfo->bitmask |= EBT_ARP_DST_IP; } + free(ipaddr); if (invert) { if (c == ARP_IP_S) arpinfo->invflags |= EBT_ARP_SRC_IP; else arpinfo->invflags |= EBT_ARP_DST_IP; } - ebt_parse_ip_address(optarg, addr, mask); break; case ARP_MAC_S: case ARP_MAC_D: diff --git a/extensions/libebt_arp.t b/extensions/libebt_arp.t index 14ff0f09..96fbce90 100644 --- a/extensions/libebt_arp.t +++ b/extensions/libebt_arp.t @@ -6,6 +6,9 @@ -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-ip-src ! 1.2.3.4/32;-p ARP --arp-ip-src ! 1.2.3.4;OK +-p ARP --arp-ip-src ! 1.2.3.4/255.255.255.0;-p ARP --arp-ip-src ! 1.2.3.0/24;OK +-p ARP --arp-ip-src ! 1.2.3.4/255.0.255.255;-p ARP --arp-ip-src ! 1.0.3.4/255.0.255.255;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 8413a5aa..d13e83c0 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -164,80 +164,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) } /* original code from ebtables: useful_functions.c */ -static int undot_ip(char *ip, unsigned char *ip2) -{ - char *p, *q, *end; - long int onebyte; - int i; - char buf[20]; - - strncpy(buf, ip, sizeof(buf) - 1); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return -1; - *q = '\0'; - onebyte = strtol(p, &end, 10); - if (*end != '\0' || onebyte > 255 || onebyte < 0) - return -1; - ip2[i] = (unsigned char)onebyte; - p = q + 1; - } - - onebyte = strtol(p, &end, 10); - if (*end != '\0' || onebyte > 255 || onebyte < 0) - return -1; - ip2[3] = (unsigned char)onebyte; - - return 0; -} - -static int ip_mask(char *mask, unsigned char *mask2) -{ - char *end; - long int bits; - uint32_t mask22; - - if (undot_ip(mask, mask2)) { - /* not the /a.b.c.e format, maybe the /x format */ - bits = strtol(mask, &end, 10); - if (*end != '\0' || bits > 32 || bits < 0) - return -1; - if (bits != 0) { - mask22 = htonl(0xFFFFFFFF << (32 - bits)); - memcpy(mask2, &mask22, 4); - } else { - mask22 = 0xFFFFFFFF; - memcpy(mask2, &mask22, 4); - } - } - return 0; -} - -static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) -{ - char *p; - - /* first the mask */ - if ((p = strrchr(address, '/')) != NULL) { - *p = '\0'; - if (ip_mask(p + 1, (unsigned char *)msk)) { - xtables_error(PARAMETER_PROBLEM, - "Problem with the IP mask '%s'", p + 1); - return; - } - } else - *msk = 0xFFFFFFFF; - - if (undot_ip(address, (unsigned char *)addr)) { - xtables_error(PARAMETER_PROBLEM, - "Problem with the IP address '%s'", address); - return; - } - *addr = *addr & *msk; -} - static char *parse_range(const char *str, unsigned int res[]) { char *next; @@ -355,18 +281,26 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data; + struct in_addr *ipaddr, ipmask; + unsigned int ipnr; switch (c) { case IP_SOURCE: if (invert) info->invflags |= EBT_IP_SOURCE; - ebt_parse_ip_address(optarg, &info->saddr, &info->smsk); + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); + info->saddr = ipaddr->s_addr; + info->smsk = ipmask.s_addr; + free(ipaddr); info->bitmask |= EBT_IP_SOURCE; break; case IP_DEST: if (invert) info->invflags |= EBT_IP_DEST; - ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk); + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); + info->daddr = ipaddr->s_addr; + info->dmsk = ipmask.s_addr; + free(ipaddr); info->bitmask |= EBT_IP_DEST; break; case IP_SPORT: -- cgit v1.2.3 From 2c6676fcedb08f08b28f2f12625f9e4d6242aff0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 11 Oct 2022 17:07:33 +0200 Subject: extensions: Collate ICMP types/codes in libxt_icmp.h Put the most extensive version of icmp_codes, icmpv6_codes and igmp_codes into the header. Have to rename the function xt_print_icmp_types's parameter to avoid a compiler warning. Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 62 ------------------------ extensions/libebt_ip6.c | 38 --------------- extensions/libip6t_icmp6.c | 42 ---------------- extensions/libipt_icmp.c | 55 --------------------- extensions/libxt_icmp.h | 116 +++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 107 insertions(+), 206 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index d13e83c0..27ae84e9 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -50,68 +50,6 @@ static const struct option brip_opts[] = { XT_GETOPT_TABLEEND, }; -static const struct xt_icmp_names icmp_codes[] = { - { "echo-reply", 0, 0, 0xFF }, - /* Alias */ { "pong", 0, 0, 0xFF }, - - { "destination-unreachable", 3, 0, 0xFF }, - { "network-unreachable", 3, 0, 0 }, - { "host-unreachable", 3, 1, 1 }, - { "protocol-unreachable", 3, 2, 2 }, - { "port-unreachable", 3, 3, 3 }, - { "fragmentation-needed", 3, 4, 4 }, - { "source-route-failed", 3, 5, 5 }, - { "network-unknown", 3, 6, 6 }, - { "host-unknown", 3, 7, 7 }, - { "network-prohibited", 3, 9, 9 }, - { "host-prohibited", 3, 10, 10 }, - { "TOS-network-unreachable", 3, 11, 11 }, - { "TOS-host-unreachable", 3, 12, 12 }, - { "communication-prohibited", 3, 13, 13 }, - { "host-precedence-violation", 3, 14, 14 }, - { "precedence-cutoff", 3, 15, 15 }, - - { "source-quench", 4, 0, 0xFF }, - - { "redirect", 5, 0, 0xFF }, - { "network-redirect", 5, 0, 0 }, - { "host-redirect", 5, 1, 1 }, - { "TOS-network-redirect", 5, 2, 2 }, - { "TOS-host-redirect", 5, 3, 3 }, - - { "echo-request", 8, 0, 0xFF }, - /* Alias */ { "ping", 8, 0, 0xFF }, - - { "router-advertisement", 9, 0, 0xFF }, - - { "router-solicitation", 10, 0, 0xFF }, - - { "time-exceeded", 11, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, - { "ttl-zero-during-transit", 11, 0, 0 }, - { "ttl-zero-during-reassembly", 11, 1, 1 }, - - { "parameter-problem", 12, 0, 0xFF }, - { "ip-header-bad", 12, 0, 0 }, - { "required-option-missing", 12, 1, 1 }, - - { "timestamp-request", 13, 0, 0xFF }, - - { "timestamp-reply", 14, 0, 0xFF }, - - { "address-mask-request", 17, 0, 0xFF }, - - { "address-mask-reply", 18, 0, 0xFF } -}; - -static const struct xt_icmp_names igmp_types[] = { - { "membership-query", 0x11 }, - { "membership-report-v1", 0x12 }, - { "membership-report-v2", 0x16 }, - { "leave-group", 0x17 }, - { "membership-report-v3", 0x22 }, -}; - static void brip_print_help(void) { printf( diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index a686a285..ac20666a 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -49,44 +49,6 @@ static const struct option brip6_opts[] = { XT_GETOPT_TABLEEND, }; -static const struct xt_icmp_names icmpv6_codes[] = { - { "destination-unreachable", 1, 0, 0xFF }, - { "no-route", 1, 0, 0 }, - { "communication-prohibited", 1, 1, 1 }, - { "address-unreachable", 1, 3, 3 }, - { "port-unreachable", 1, 4, 4 }, - - { "packet-too-big", 2, 0, 0xFF }, - - { "time-exceeded", 3, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, - { "ttl-zero-during-transit", 3, 0, 0 }, - { "ttl-zero-during-reassembly", 3, 1, 1 }, - - { "parameter-problem", 4, 0, 0xFF }, - { "bad-header", 4, 0, 0 }, - { "unknown-header-type", 4, 1, 1 }, - { "unknown-option", 4, 2, 2 }, - - { "echo-request", 128, 0, 0xFF }, - /* Alias */ { "ping", 128, 0, 0xFF }, - - { "echo-reply", 129, 0, 0xFF }, - /* Alias */ { "pong", 129, 0, 0xFF }, - - { "router-solicitation", 133, 0, 0xFF }, - - { "router-advertisement", 134, 0, 0xFF }, - - { "neighbour-solicitation", 135, 0, 0xFF }, - /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, - - { "neighbour-advertisement", 136, 0, 0xFF }, - /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, - - { "redirect", 137, 0, 0xFF }, -}; - static void parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) { diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index cc7bfaeb..44f71095 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -12,48 +12,6 @@ enum { O_ICMPV6_TYPE = 0, }; -static const struct xt_icmp_names icmpv6_codes[] = { - { "destination-unreachable", 1, 0, 0xFF }, - { "no-route", 1, 0, 0 }, - { "communication-prohibited", 1, 1, 1 }, - { "beyond-scope", 1, 2, 2 }, - { "address-unreachable", 1, 3, 3 }, - { "port-unreachable", 1, 4, 4 }, - { "failed-policy", 1, 5, 5 }, - { "reject-route", 1, 6, 6 }, - - { "packet-too-big", 2, 0, 0xFF }, - - { "time-exceeded", 3, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, - { "ttl-zero-during-transit", 3, 0, 0 }, - { "ttl-zero-during-reassembly", 3, 1, 1 }, - - { "parameter-problem", 4, 0, 0xFF }, - { "bad-header", 4, 0, 0 }, - { "unknown-header-type", 4, 1, 1 }, - { "unknown-option", 4, 2, 2 }, - - { "echo-request", 128, 0, 0xFF }, - /* Alias */ { "ping", 128, 0, 0xFF }, - - { "echo-reply", 129, 0, 0xFF }, - /* Alias */ { "pong", 129, 0, 0xFF }, - - { "router-solicitation", 133, 0, 0xFF }, - - { "router-advertisement", 134, 0, 0xFF }, - - { "neighbour-solicitation", 135, 0, 0xFF }, - /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, - - { "neighbour-advertisement", 136, 0, 0xFF }, - /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, - - { "redirect", 137, 0, 0xFF }, - -}; - static void icmp6_help(void) { printf( diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index e5e23661..f0e83887 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -19,61 +19,6 @@ enum { O_ICMP_TYPE = 0, }; -static const struct xt_icmp_names icmp_codes[] = { - { "any", 0xFF, 0, 0xFF }, - { "echo-reply", 0, 0, 0xFF }, - /* Alias */ { "pong", 0, 0, 0xFF }, - - { "destination-unreachable", 3, 0, 0xFF }, - { "network-unreachable", 3, 0, 0 }, - { "host-unreachable", 3, 1, 1 }, - { "protocol-unreachable", 3, 2, 2 }, - { "port-unreachable", 3, 3, 3 }, - { "fragmentation-needed", 3, 4, 4 }, - { "source-route-failed", 3, 5, 5 }, - { "network-unknown", 3, 6, 6 }, - { "host-unknown", 3, 7, 7 }, - { "network-prohibited", 3, 9, 9 }, - { "host-prohibited", 3, 10, 10 }, - { "TOS-network-unreachable", 3, 11, 11 }, - { "TOS-host-unreachable", 3, 12, 12 }, - { "communication-prohibited", 3, 13, 13 }, - { "host-precedence-violation", 3, 14, 14 }, - { "precedence-cutoff", 3, 15, 15 }, - - { "source-quench", 4, 0, 0xFF }, - - { "redirect", 5, 0, 0xFF }, - { "network-redirect", 5, 0, 0 }, - { "host-redirect", 5, 1, 1 }, - { "TOS-network-redirect", 5, 2, 2 }, - { "TOS-host-redirect", 5, 3, 3 }, - - { "echo-request", 8, 0, 0xFF }, - /* Alias */ { "ping", 8, 0, 0xFF }, - - { "router-advertisement", 9, 0, 0xFF }, - - { "router-solicitation", 10, 0, 0xFF }, - - { "time-exceeded", 11, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, - { "ttl-zero-during-transit", 11, 0, 0 }, - { "ttl-zero-during-reassembly", 11, 1, 1 }, - - { "parameter-problem", 12, 0, 0xFF }, - { "ip-header-bad", 12, 0, 0 }, - { "required-option-missing", 12, 1, 1 }, - - { "timestamp-request", 13, 0, 0xFF }, - - { "timestamp-reply", 14, 0, 0xFF }, - - { "address-mask-request", 17, 0, 0xFF }, - - { "address-mask-reply", 18, 0, 0xFF } -}; - static void icmp_help(void) { printf( diff --git a/extensions/libxt_icmp.h b/extensions/libxt_icmp.h index 5820206e..d6d9f9b6 100644 --- a/extensions/libxt_icmp.h +++ b/extensions/libxt_icmp.h @@ -1,25 +1,123 @@ -struct xt_icmp_names { +static const struct xt_icmp_names { const char *name; uint8_t type; uint8_t code_min, code_max; +} icmp_codes[] = { + { "any", 0xFF, 0, 0xFF }, + { "echo-reply", 0, 0, 0xFF }, + /* Alias */ { "pong", 0, 0, 0xFF }, + + { "destination-unreachable", 3, 0, 0xFF }, + { "network-unreachable", 3, 0, 0 }, + { "host-unreachable", 3, 1, 1 }, + { "protocol-unreachable", 3, 2, 2 }, + { "port-unreachable", 3, 3, 3 }, + { "fragmentation-needed", 3, 4, 4 }, + { "source-route-failed", 3, 5, 5 }, + { "network-unknown", 3, 6, 6 }, + { "host-unknown", 3, 7, 7 }, + { "network-prohibited", 3, 9, 9 }, + { "host-prohibited", 3, 10, 10 }, + { "TOS-network-unreachable", 3, 11, 11 }, + { "TOS-host-unreachable", 3, 12, 12 }, + { "communication-prohibited", 3, 13, 13 }, + { "host-precedence-violation", 3, 14, 14 }, + { "precedence-cutoff", 3, 15, 15 }, + + { "source-quench", 4, 0, 0xFF }, + + { "redirect", 5, 0, 0xFF }, + { "network-redirect", 5, 0, 0 }, + { "host-redirect", 5, 1, 1 }, + { "TOS-network-redirect", 5, 2, 2 }, + { "TOS-host-redirect", 5, 3, 3 }, + + { "echo-request", 8, 0, 0xFF }, + /* Alias */ { "ping", 8, 0, 0xFF }, + + { "router-advertisement", 9, 0, 0xFF }, + + { "router-solicitation", 10, 0, 0xFF }, + + { "time-exceeded", 11, 0, 0xFF }, + /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, + { "ttl-zero-during-transit", 11, 0, 0 }, + { "ttl-zero-during-reassembly", 11, 1, 1 }, + + { "parameter-problem", 12, 0, 0xFF }, + { "ip-header-bad", 12, 0, 0 }, + { "required-option-missing", 12, 1, 1 }, + + { "timestamp-request", 13, 0, 0xFF }, + + { "timestamp-reply", 14, 0, 0xFF }, + + { "address-mask-request", 17, 0, 0xFF }, + + { "address-mask-reply", 18, 0, 0xFF } +}, icmpv6_codes[] = { + { "destination-unreachable", 1, 0, 0xFF }, + { "no-route", 1, 0, 0 }, + { "communication-prohibited", 1, 1, 1 }, + { "beyond-scope", 1, 2, 2 }, + { "address-unreachable", 1, 3, 3 }, + { "port-unreachable", 1, 4, 4 }, + { "failed-policy", 1, 5, 5 }, + { "reject-route", 1, 6, 6 }, + + { "packet-too-big", 2, 0, 0xFF }, + + { "time-exceeded", 3, 0, 0xFF }, + /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, + { "ttl-zero-during-transit", 3, 0, 0 }, + { "ttl-zero-during-reassembly", 3, 1, 1 }, + + { "parameter-problem", 4, 0, 0xFF }, + { "bad-header", 4, 0, 0 }, + { "unknown-header-type", 4, 1, 1 }, + { "unknown-option", 4, 2, 2 }, + + { "echo-request", 128, 0, 0xFF }, + /* Alias */ { "ping", 128, 0, 0xFF }, + + { "echo-reply", 129, 0, 0xFF }, + /* Alias */ { "pong", 129, 0, 0xFF }, + + { "router-solicitation", 133, 0, 0xFF }, + + { "router-advertisement", 134, 0, 0xFF }, + + { "neighbour-solicitation", 135, 0, 0xFF }, + /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, + + { "neighbour-advertisement", 136, 0, 0xFF }, + /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, + + { "redirect", 137, 0, 0xFF }, +}, igmp_types[] = { + { "membership-query", 0x11 }, + { "membership-report-v1", 0x12 }, + { "membership-report-v2", 0x16 }, + { "leave-group", 0x17 }, + { "membership-report-v3", 0x22 }, }; -static void xt_print_icmp_types(const struct xt_icmp_names *icmp_codes, +static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes, unsigned int n_codes) { unsigned int i; for (i = 0; i < n_codes; ++i) { - if (i && icmp_codes[i].type == icmp_codes[i-1].type) { - if (icmp_codes[i].code_min == icmp_codes[i-1].code_min - && (icmp_codes[i].code_max - == icmp_codes[i-1].code_max)) - printf(" (%s)", icmp_codes[i].name); + if (i && _icmp_codes[i].type == _icmp_codes[i-1].type) { + if (_icmp_codes[i].code_min == _icmp_codes[i-1].code_min + && (_icmp_codes[i].code_max + == _icmp_codes[i-1].code_max)) + printf(" (%s)", _icmp_codes[i].name); else - printf("\n %s", icmp_codes[i].name); + printf("\n %s", _icmp_codes[i].name); } else - printf("\n%s", icmp_codes[i].name); + printf("\n%s", _icmp_codes[i].name); } printf("\n"); } -- cgit v1.2.3 From be8c6056040848b019e76e8b578598b35bae2655 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Oct 2022 02:02:38 +0200 Subject: extensions: Unify ICMP parser into libxt_icmp.h Merge all four copies of the ICMP/ICMPv6/IGMP parameter parsing code. Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 82 +---------------------------- extensions/libebt_ip6.c | 73 +------------------------- extensions/libip6t_icmp6.c | 55 +------------------- extensions/libipt_icmp.c | 55 +------------------- extensions/libxt_icmp.h | 126 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 260 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index 27ae84e9..fd87dae7 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -102,82 +102,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) } /* original code from ebtables: useful_functions.c */ -static char *parse_range(const char *str, unsigned int res[]) -{ - char *next; - - if (!xtables_strtoui(str, &next, &res[0], 0, 255)) - return NULL; - - res[1] = res[0]; - if (*next == ':') { - str = next + 1; - if (!xtables_strtoui(str, &next, &res[1], 0, 255)) - return NULL; - } - - return next; -} - -static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes, - const char *icmptype, uint8_t type[], uint8_t code[]) -{ - unsigned int match = n_codes; - unsigned int i, number[2]; - - for (i = 0; i < n_codes; i++) { - if (strncasecmp(codes[i].name, icmptype, strlen(icmptype))) - continue; - if (match != n_codes) - xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':" - " `%s' or `%s'?", - icmptype, codes[match].name, - codes[i].name); - match = i; - } - - if (match < n_codes) { - type[0] = type[1] = codes[match].type; - if (code) { - code[0] = codes[match].code_min; - code[1] = codes[match].code_max; - } - } else { - char *next = parse_range(icmptype, number); - if (!next) { - xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'", - icmptype); - return -1; - } - - type[0] = (uint8_t) number[0]; - type[1] = (uint8_t) number[1]; - switch (*next) { - case 0: - if (code) { - code[0] = 0; - code[1] = 255; - } - return 0; - case '/': - if (code) { - next = parse_range(next+1, number); - code[0] = (uint8_t) number[0]; - code[1] = (uint8_t) number[1]; - if (next == NULL) - return -1; - if (next && *next == 0) - return 0; - } - /* fallthrough */ - default: - xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); - return -1; - } - } - return 0; -} - static void print_icmp_code(uint8_t *code) { if (!code) @@ -256,15 +180,13 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags, case IP_EBT_ICMP: if (invert) info->invflags |= EBT_IP_ICMP; - ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg, - info->icmp_type, info->icmp_code); + ebt_parse_icmp(optarg, info->icmp_type, info->icmp_code); info->bitmask |= EBT_IP_ICMP; break; case IP_EBT_IGMP: if (invert) info->invflags |= EBT_IP_IGMP; - ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg, - info->igmp_type, NULL); + ebt_parse_igmp(optarg, info->igmp_type); info->bitmask |= EBT_IP_IGMP; break; case IP_EBT_TOS: { diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index ac20666a..18bb2720 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -72,76 +72,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) free(buffer); } -static char *parse_range(const char *str, unsigned int res[]) -{ - char *next; - - if (!xtables_strtoui(str, &next, &res[0], 0, 255)) - return NULL; - - res[1] = res[0]; - if (*next == ':') { - str = next + 1; - if (!xtables_strtoui(str, &next, &res[1], 0, 255)) - return NULL; - } - - return next; -} - -static int -parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); - unsigned int match = limit; - unsigned int i, number[2]; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))) - continue; - if (match != limit) - xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMPv6 type `%s':" - " `%s' or `%s'?", - icmpv6type, icmpv6_codes[match].name, - icmpv6_codes[i].name); - match = i; - } - - if (match < limit) { - type[0] = type[1] = icmpv6_codes[match].type; - code[0] = icmpv6_codes[match].code_min; - code[1] = icmpv6_codes[match].code_max; - } else { - char *next = parse_range(icmpv6type, number); - if (!next) { - xtables_error(PARAMETER_PROBLEM, "Unknown ICMPv6 type `%s'", - icmpv6type); - return -1; - } - type[0] = (uint8_t) number[0]; - type[1] = (uint8_t) number[1]; - switch (*next) { - case 0: - code[0] = 0; - code[1] = 255; - return 0; - case '/': - next = parse_range(next+1, number); - code[0] = (uint8_t) number[0]; - code[1] = (uint8_t) number[1]; - if (next == NULL) - return -1; - if (next && *next == 0) - return 0; - /* fallthrough */ - default: - xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); - return -1; - } - } - return 0; -} - static void print_port_range(uint16_t *ports) { if (ports[0] == ports[1]) @@ -266,8 +196,7 @@ brip6_parse(int c, char **argv, int invert, unsigned int *flags, case IP_ICMP6: if (invert) info->invflags |= EBT_IP6_ICMP6; - if (parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code)) - return 0; + ebt_parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code); info->bitmask |= EBT_IP6_ICMP6; break; case IP_TCLASS: diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index 44f71095..439291ea 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -28,59 +28,6 @@ static const struct xt_option_entry icmp6_opts[] = { XTOPT_TABLEEND, }; -static void -parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); - unsigned int match = limit; - unsigned int i; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)) - == 0) { - if (match != limit) - xtables_error(PARAMETER_PROBLEM, - "Ambiguous ICMPv6 type `%s':" - " `%s' or `%s'?", - icmpv6type, - icmpv6_codes[match].name, - icmpv6_codes[i].name); - match = i; - } - } - - if (match != limit) { - *type = icmpv6_codes[match].type; - code[0] = icmpv6_codes[match].code_min; - code[1] = icmpv6_codes[match].code_max; - } else { - char *slash; - char buffer[strlen(icmpv6type) + 1]; - unsigned int number; - - strcpy(buffer, icmpv6type); - slash = strchr(buffer, '/'); - - if (slash) - *slash = '\0'; - - if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMPv6 type `%s'\n", buffer); - *type = number; - if (slash) { - if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMPv6 code `%s'\n", - slash+1); - code[0] = code[1] = number; - } else { - code[0] = 0; - code[1] = 0xFF; - } - } -} - static void icmp6_init(struct xt_entry_match *m) { struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data; @@ -93,7 +40,7 @@ static void icmp6_parse(struct xt_option_call *cb) struct ip6t_icmp *icmpv6info = cb->data; xtables_option_parse(cb); - parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); + ipt_parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); if (cb->invert) icmpv6info->invflags |= IP6T_ICMP_INV; } diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index f0e83887..b0318aeb 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -35,59 +35,6 @@ static const struct xt_option_entry icmp_opts[] = { XTOPT_TABLEEND, }; -static void -parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmp_codes); - unsigned int match = limit; - unsigned int i; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)) - == 0) { - if (match != limit) - xtables_error(PARAMETER_PROBLEM, - "Ambiguous ICMP type `%s':" - " `%s' or `%s'?", - icmptype, - icmp_codes[match].name, - icmp_codes[i].name); - match = i; - } - } - - if (match != limit) { - *type = icmp_codes[match].type; - code[0] = icmp_codes[match].code_min; - code[1] = icmp_codes[match].code_max; - } else { - char *slash; - char buffer[strlen(icmptype) + 1]; - unsigned int number; - - strcpy(buffer, icmptype); - slash = strchr(buffer, '/'); - - if (slash) - *slash = '\0'; - - if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMP type `%s'\n", buffer); - *type = number; - if (slash) { - if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMP code `%s'\n", - slash+1); - code[0] = code[1] = number; - } else { - code[0] = 0; - code[1] = 0xFF; - } - } -} - static void icmp_init(struct xt_entry_match *m) { struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; @@ -101,7 +48,7 @@ static void icmp_parse(struct xt_option_call *cb) struct ipt_icmp *icmpinfo = cb->data; xtables_option_parse(cb); - parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code); + ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code); if (cb->invert) icmpinfo->invflags |= IPT_ICMP_INV; } diff --git a/extensions/libxt_icmp.h b/extensions/libxt_icmp.h index d6d9f9b6..a763e50c 100644 --- a/extensions/libxt_icmp.h +++ b/extensions/libxt_icmp.h @@ -102,6 +102,132 @@ static const struct xt_icmp_names { { "membership-report-v3", 0x22 }, }; +static inline char *parse_range(const char *str, unsigned int res[]) +{ + char *next; + + if (!xtables_strtoui(str, &next, &res[0], 0, 255)) + return NULL; + + res[1] = res[0]; + if (*next == ':') { + str = next + 1; + if (!xtables_strtoui(str, &next, &res[1], 0, 255)) + return NULL; + } + + return next; +} + +static void +__parse_icmp(const struct xt_icmp_names codes[], size_t n_codes, + const char *codes_name, const char *fmtstring, + uint8_t type[], uint8_t code[]) +{ + unsigned int match = n_codes; + unsigned int i, number[2]; + + for (i = 0; i < n_codes; i++) { + if (strncasecmp(codes[i].name, fmtstring, strlen(fmtstring))) + continue; + if (match != n_codes) + xtables_error(PARAMETER_PROBLEM, + "Ambiguous %s type `%s': `%s' or `%s'?", + codes_name, fmtstring, codes[match].name, + codes[i].name); + match = i; + } + + if (match < n_codes) { + type[0] = type[1] = codes[match].type; + if (code) { + code[0] = codes[match].code_min; + code[1] = codes[match].code_max; + } + } else { + char *next = parse_range(fmtstring, number); + if (!next) + xtables_error(PARAMETER_PROBLEM, "Unknown %s type `%s'", + codes_name, fmtstring); + type[0] = (uint8_t) number[0]; + type[1] = (uint8_t) number[1]; + switch (*next) { + case 0: + if (code) { + code[0] = 0; + code[1] = 255; + } + return; + case '/': + if (!code) + break; + + next = parse_range(next + 1, number); + if (!next) + xtables_error(PARAMETER_PROBLEM, + "Unknown %s code `%s'", + codes_name, fmtstring); + code[0] = (uint8_t) number[0]; + code[1] = (uint8_t) number[1]; + if (!*next) + break; + /* fallthrough */ + default: + xtables_error(PARAMETER_PROBLEM, + "unknown character %c", *next); + } + } +} + +static inline void +__ipt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes, + const char *codes_name, const char *fmtstr, + uint8_t *type, uint8_t code[]) +{ + uint8_t types[2]; + + __parse_icmp(codes, n_codes, codes_name, fmtstr, types, code); + if (types[1] != types[0]) + xtables_error(PARAMETER_PROBLEM, + "%s type range not supported", codes_name); + *type = types[0]; +} + +static inline void +ipt_parse_icmp(const char *str, uint8_t *type, uint8_t code[]) +{ + __ipt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), + "ICMP", str, type, code); +} + +static inline void +ipt_parse_icmpv6(const char *str, uint8_t *type, uint8_t code[]) +{ + __ipt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), + "ICMPv6", str, type, code); +} + +static inline void +ebt_parse_icmp(const char *str, uint8_t type[], uint8_t code[]) +{ + __parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), + "ICMP", str, type, code); +} + +static inline void +ebt_parse_icmpv6(const char *str, uint8_t type[], uint8_t code[]) +{ + __parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), + "ICMPv6", str, type, code); +} + +static inline void +ebt_parse_igmp(const char *str, uint8_t type[]) +{ + __parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), + "IGMP", str, type, NULL); +} + static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes, unsigned int n_codes) { -- cgit v1.2.3 From 66b4a68de2212f3f872dc1b0e36aa8e76c70659d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 7 Jan 2022 16:26:30 +0100 Subject: Drop extra newline from xtables_error() calls Since basic_exit_err() appends a newline to the message itself, drop explicit ones. While being at it, fix indentation and join texts split over multiple lines. Signed-off-by: Phil Sutter --- extensions/dscp_helper.c | 4 +-- extensions/libebt_among.c | 4 +-- extensions/libip6t_mh.c | 2 +- extensions/libipt_CLUSTERIP.c | 10 ++++--- extensions/libxt_CONNSECMARK.c | 3 ++- extensions/libxt_CT.c | 2 +- extensions/libxt_SECMARK.c | 2 +- extensions/libxt_bpf.c | 3 +-- extensions/libxt_hashlimit.c | 8 +++--- extensions/libxt_limit.c | 4 +-- extensions/libxt_sctp.c | 9 +++---- extensions/libxt_set.c | 59 ++++++++++++++++------------------------- iptables/ip6tables.c | 4 +-- iptables/iptables-restore.c | 38 +++++++++++++------------- iptables/iptables-save.c | 5 ++-- iptables/iptables-xml.c | 16 +++++------ iptables/iptables.c | 4 +-- iptables/nft-cache.c | 3 ++- iptables/nft.c | 2 +- iptables/xshared.c | 30 ++++++++++----------- iptables/xtables-eb-translate.c | 2 +- iptables/xtables-eb.c | 2 +- iptables/xtables-restore.c | 26 +++++++++--------- libxtables/xtoptions.c | 4 +-- 24 files changed, 115 insertions(+), 131 deletions(-) diff --git a/extensions/dscp_helper.c b/extensions/dscp_helper.c index 75b1fece..1f20b2a5 100644 --- a/extensions/dscp_helper.c +++ b/extensions/dscp_helper.c @@ -58,7 +58,7 @@ class_to_dscp(const char *name) } xtables_error(PARAMETER_PROBLEM, - "Invalid DSCP value `%s'\n", name); + "Invalid DSCP value `%s'", name); } @@ -73,7 +73,7 @@ dscp_to_name(unsigned int dscp) return ds_classes[i].name; xtables_error(PARAMETER_PROBLEM, - "Invalid DSCP value `%d'\n", dscp); + "Invalid DSCP value `%d'", dscp); } #endif diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c index 1eab2019..a80fb804 100644 --- a/extensions/libebt_among.c +++ b/extensions/libebt_among.c @@ -68,12 +68,12 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip) if (!inet_pton(AF_INET, sep + 1, &pair->in)) xtables_error(PARAMETER_PROBLEM, - "Invalid IP address '%s'\n", sep + 1); + "Invalid IP address '%s'", sep + 1); } ether = ether_aton(buf); if (!ether) xtables_error(PARAMETER_PROBLEM, - "Invalid MAC address '%s'\n", buf); + "Invalid MAC address '%s'", buf); memcpy(&pair->ether, ether, sizeof(*ether)); } diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c index 64675405..1410d324 100644 --- a/extensions/libip6t_mh.c +++ b/extensions/libip6t_mh.c @@ -97,7 +97,7 @@ static unsigned int name_to_type(const char *name) if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX)) xtables_error(PARAMETER_PROBLEM, - "Invalid MH type `%s'\n", name); + "Invalid MH type `%s'", name); return number; } } diff --git a/extensions/libipt_CLUSTERIP.c b/extensions/libipt_CLUSTERIP.c index f4b638b2..b207cde3 100644 --- a/extensions/libipt_CLUSTERIP.c +++ b/extensions/libipt_CLUSTERIP.c @@ -87,12 +87,13 @@ static void CLUSTERIP_parse(struct xt_option_call *cb) else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0) cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT; else - xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n", - cb->arg); + xtables_error(PARAMETER_PROBLEM, + "Unknown hashmode \"%s\"", cb->arg); break; case O_CLUSTERMAC: if (!(cipinfo->clustermac[0] & 0x01)) - xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n"); + xtables_error(PARAMETER_PROBLEM, + "MAC has to be a multicast ethernet address"); break; case O_LOCAL_NODE: cipinfo->num_local_nodes = 1; @@ -107,7 +108,8 @@ static void CLUSTERIP_check(struct xt_fcheck_call *cb) if ((cb->xflags & F_FULL) == F_FULL) return; - xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n"); + xtables_error(PARAMETER_PROBLEM, + "CLUSTERIP target: Invalid parameter combination"); } static const char *hashmode2str(enum clusterip_hashmode mode) diff --git a/extensions/libxt_CONNSECMARK.c b/extensions/libxt_CONNSECMARK.c index 0b3cd79d..6da589d3 100644 --- a/extensions/libxt_CONNSECMARK.c +++ b/extensions/libxt_CONNSECMARK.c @@ -66,7 +66,8 @@ static void print_connsecmark(const struct xt_connsecmark_target_info *info) break; default: - xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode); + xtables_error(OTHER_PROBLEM, + PFX "invalid mode %hhu", info->mode); } } diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c index fbbbe266..18824665 100644 --- a/extensions/libxt_CT.c +++ b/extensions/libxt_CT.c @@ -117,7 +117,7 @@ static void ct_parse_zone_id(const char *opt, unsigned int opt_id, if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX)) xtables_error(PARAMETER_PROBLEM, - "Cannot parse %s as a zone ID\n", opt); + "Cannot parse %s as a zone ID", opt); *zone_id = (uint16_t)val; } diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c index 24249bd6..a4ee60f0 100644 --- a/extensions/libxt_SECMARK.c +++ b/extensions/libxt_SECMARK.c @@ -60,7 +60,7 @@ static void print_secmark(__u8 mode, const char *secctx) break; default: - xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", mode); + xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu", mode); } } diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c index eeae86e5..5e035837 100644 --- a/extensions/libxt_bpf.c +++ b/extensions/libxt_bpf.c @@ -83,8 +83,7 @@ static int bpf_obj_get_readonly(const char *filepath) attr.file_flags = 0; return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); #else - xtables_error(OTHER_PROBLEM, - "No bpf header, kernel headers too old?\n"); + xtables_error(OTHER_PROBLEM, "No bpf header, kernel headers too old?"); return -EINVAL; #endif } diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c index 3f3c4301..93ee1c32 100644 --- a/extensions/libxt_hashlimit.c +++ b/extensions/libxt_hashlimit.c @@ -356,12 +356,12 @@ static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata * tmp = (uint64_t) r * factor; if (tmp > max) xtables_error(PARAMETER_PROBLEM, - "Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n", - tmp, max); + "Rate value too large \"%"PRIu64"\" (max %"PRIu64")", + tmp, max); tmp = bytes_to_cost(tmp); if (tmp == 0) - xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate); + xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"", rate); ud->mult = XT_HASHLIMIT_BYTE_EXPIRE; @@ -407,7 +407,7 @@ int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int r * The rate maps to infinity. (1/day is the minimum they can * specify, so we are ok at that end). */ - xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); + xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate); if(revision == 1) *((uint32_t*)val) = tmp; diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c index 1b324657..e6ec67f3 100644 --- a/extensions/libxt_limit.c +++ b/extensions/libxt_limit.c @@ -77,7 +77,7 @@ int parse_rate(const char *rate, uint32_t *val) * The rate maps to infinity. (1/day is the minimum they can * specify, so we are ok at that end). */ - xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); + xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate); return 1; } @@ -93,7 +93,7 @@ static void limit_init(struct xt_entry_match *m) /* FIXME: handle overflow: if (r->avg*r->burst/r->burst != r->avg) xtables_error(PARAMETER_PROBLEM, - "Sorry: burst too large for that avg rate.\n"); + "Sorry: burst too large for that avg rate."); */ static void limit_parse(struct xt_option_call *cb) diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index 3fb6cf1a..8f069a43 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -144,10 +144,8 @@ save_chunk_flag_info(struct xt_sctp_flag_info *flag_info, } if (*flag_count == XT_NUM_SCTP_FLAGS) { - xtables_error (PARAMETER_PROBLEM, - "Number of chunk types with flags exceeds currently allowed limit." - "Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and" - "recompiling both the kernel space and user space modules\n"); + xtables_error(PARAMETER_PROBLEM, + "Number of chunk types with flags exceeds currently allowed limit. Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and recompiling both the kernel space and user space modules"); } flag_info[*flag_count].chunktype = chunktype; @@ -219,7 +217,8 @@ parse_sctp_chunk(struct xt_sctp_info *einfo, isupper(chunk_flags[j])); } else { xtables_error(PARAMETER_PROBLEM, - "Invalid flags for chunk type %d\n", i); + "Invalid flags for chunk type %d", + i); } } } diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c index a2137ab1..471bde8a 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -334,8 +334,7 @@ parse_counter(const char *opt) if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX)) xtables_error(PARAMETER_PROBLEM, - "Cannot parse %s as a counter value\n", - opt); + "Cannot parse %s as a counter value", opt); return (uint64_t)value; } @@ -354,60 +353,54 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags, case '0': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-gt option cannot be inverted\n"); + "--bytes-gt option cannot be inverted"); info->bytes.op = IPSET_COUNTER_GT; info->bytes.value = parse_counter(optarg); break; case '9': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-lt option cannot be inverted\n"); + "--bytes-lt option cannot be inverted"); info->bytes.op = IPSET_COUNTER_LT; info->bytes.value = parse_counter(optarg); break; case '8': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->bytes.value = parse_counter(optarg); break; case '7': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-gt option cannot be inverted\n"); + "--packets-gt option cannot be inverted"); info->packets.op = IPSET_COUNTER_GT; info->packets.value = parse_counter(optarg); break; case '6': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-lt option cannot be inverted\n"); + "--packets-lt option cannot be inverted"); info->packets.op = IPSET_COUNTER_LT; info->packets.value = parse_counter(optarg); break; case '5': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->packets.value = parse_counter(optarg); break; @@ -418,7 +411,7 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags, case '3': if (invert) xtables_error(PARAMETER_PROBLEM, - "--return-nomatch flag cannot be inverted\n"); + "--return-nomatch flag cannot be inverted"); info->flags |= IPSET_FLAG_RETURN_NOMATCH; break; case '2': @@ -523,60 +516,54 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags, case '0': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-gt option cannot be inverted\n"); + "--bytes-gt option cannot be inverted"); info->bytes.op = IPSET_COUNTER_GT; info->bytes.value = parse_counter(optarg); break; case '9': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-lt option cannot be inverted\n"); + "--bytes-lt option cannot be inverted"); info->bytes.op = IPSET_COUNTER_LT; info->bytes.value = parse_counter(optarg); break; case '8': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->bytes.value = parse_counter(optarg); break; case '7': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-gt option cannot be inverted\n"); + "--packets-gt option cannot be inverted"); info->packets.op = IPSET_COUNTER_GT; info->packets.value = parse_counter(optarg); break; case '6': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-lt option cannot be inverted\n"); + "--packets-lt option cannot be inverted"); info->packets.op = IPSET_COUNTER_LT; info->packets.value = parse_counter(optarg); break; case '5': if (info->packets.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --packets-[eq|lt|gt]" - " is allowed\n"); + "only one of the --packets-[eq|lt|gt] is allowed"); info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->packets.value = parse_counter(optarg); break; @@ -587,7 +574,7 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags, case '3': if (invert) xtables_error(PARAMETER_PROBLEM, - "--return-nomatch flag cannot be inverted\n"); + "--return-nomatch flag cannot be inverted"); info->flags |= IPSET_FLAG_RETURN_NOMATCH; break; case '2': diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index ae267035..062b2b15 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -766,8 +766,8 @@ int do_command6(int argc, char *argv[], char **table, #ifdef IP6T_F_GOTO if (cs.fw6.ipv6.flags & IP6T_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", - cs.jumpto); + "goto '%s' is not a chain", + cs.jumpto); #endif xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 4410a587..05661bf6 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -78,8 +78,9 @@ create_handle(const struct iptables_restore_cb *cb, const char *tablename) } if (!handle) - xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize " - "table '%s'\n", xt_params->program_name, tablename); + xtables_error(PARAMETER_PROBLEM, + "%s: unable to initialize table '%s'", + xt_params->program_name, tablename); return handle; } @@ -209,8 +210,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, 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); + "%s: line %u table name invalid", + xt_params->program_name, line); strncpy(curtable, table, XT_TABLE_MAXNAMELEN); curtable[XT_TABLE_MAXNAMELEN] = '\0'; @@ -249,8 +250,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, 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); + "%s: line %u chain name invalid", + xt_params->program_name, line); if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -263,16 +264,14 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, DEBUGP("Flushing existing user defined chain '%s'\n", chain); if (!cb->ops->flush_entries(chain, handle)) xtables_error(PARAMETER_PROBLEM, - "error flushing chain " - "'%s':%s\n", chain, - strerror(errno)); + "error flushing chain '%s':%s", + chain, strerror(errno)); } else { DEBUGP("Creating new chain '%s'\n", chain); if (!cb->ops->create_chain(chain, handle)) xtables_error(PARAMETER_PROBLEM, - "error creating chain " - "'%s':%s\n", chain, - strerror(errno)); + "error creating chain '%s':%s", + chain, strerror(errno)); } } @@ -280,8 +279,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, 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); + "%s: line %u policy invalid", + xt_params->program_name, line); if (strcmp(policy, "-") != 0) { struct xt_counters count = {}; @@ -292,8 +291,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, if (!ctrs || !parse_counters(ctrs, &count)) xtables_error(PARAMETER_PROBLEM, - "invalid policy counters " - "for chain '%s'\n", chain); + "invalid policy counters for chain '%s'", + chain); } DEBUGP("Setting policy of chain %s to %s\n", @@ -302,10 +301,9 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, 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, - cb->ops->strerror(errno)); + "Can't set policy `%s' on `%s' line %u: %s", + policy, chain, line, + cb->ops->strerror(errno)); } xtables_announce_chain(chain); diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index a8dded63..094adf22 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -61,8 +61,7 @@ for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename), while (fgets(tablename, sizeof(tablename), procfile)) { if (tablename[strlen(tablename) - 1] != '\n') xtables_error(OTHER_PROBLEM, - "Badly formed tablename `%s'\n", - tablename); + "Badly formed tablename `%s'", tablename); tablename[strlen(tablename) - 1] = '\0'; ret &= func(cb, tablename); } @@ -85,7 +84,7 @@ static int do_output(struct iptables_save_cb *cb, const char *tablename) h = cb->ops->init(tablename); } if (!h) - xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n", + xtables_error(OTHER_PROBLEM, "Cannot initialize: %s", cb->ops->strerror(errno)); time_t now = time(NULL); diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c index 6cf059fb..d28cf748 100644 --- a/iptables/iptables-xml.c +++ b/iptables/iptables-xml.c @@ -210,8 +210,8 @@ saveChain(char *chain, char *policy, struct xt_counters *ctr) { if (nextChain >= maxChains) xtables_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - prog_name, line); + "%s: line %u chain name invalid", + prog_name, line); chains[nextChain].chain = xtables_strdup(chain); chains[nextChain].policy = xtables_strdup(policy); @@ -610,8 +610,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, table '%s'\n", line, table); if (!table) xtables_error(PARAMETER_PROBLEM, - "%s: line %u table name invalid\n", - prog_name, line); + "%s: line %u table name invalid", + prog_name, line); openTable(table); @@ -626,8 +626,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) xtables_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - prog_name, line); + "%s: line %u chain name invalid", + prog_name, line); DEBUGP("Creating new chain '%s'\n", chain); @@ -635,8 +635,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) xtables_error(PARAMETER_PROBLEM, - "%s: line %u policy invalid\n", - prog_name, line); + "%s: line %u policy invalid", + prog_name, line); ctrs = strtok(NULL, " \t\n"); parse_counters(ctrs, &count); diff --git a/iptables/iptables.c b/iptables/iptables.c index 591ec178..0351b39f 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -761,8 +761,8 @@ int do_command4(int argc, char *argv[], char **table, #ifdef IPT_F_GOTO if (cs.fw.ip.flags & IPT_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", - cs.jumpto); + "goto '%s' is not a chain", + cs.jumpto); #endif xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 608e42a7..2403508c 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -105,7 +105,8 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid) return; xtables_error(RESOURCE_PROBLEM, - "Could not fetch rule set generation id: %s\n", nft_strerror(errno)); + "Could not fetch rule set generation id: %s", + nft_strerror(errno)); } static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) diff --git a/iptables/nft.c b/iptables/nft.c index 09cb19c9..b65da371 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3857,6 +3857,6 @@ void nft_assert_table_compatible(struct nft_handle *h, chain = ""; } xtables_error(OTHER_PROBLEM, - "%s%s%stable `%s' is incompatible, use 'nft' tool.\n", + "%s%s%stable `%s' is incompatible, use 'nft' tool.", pfx, chain, sfx, table); } diff --git a/iptables/xshared.c b/iptables/xshared.c index 0beacee6..d400dc59 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -400,15 +400,15 @@ bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line ptr = strchr(buffer, ']'); if (!ptr) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line); pcnt = strtok(buffer+1, ":"); if (!pcnt) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :", line); bcnt = strtok(NULL, "]"); if (!bcnt) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line); *pcntp = pcnt; *bcntp = bcnt; @@ -433,10 +433,10 @@ void add_argv(struct argv_store *store, const char *what, int quoted) if (store->argc + 1 >= MAX_ARGC) xtables_error(PARAMETER_PROBLEM, - "Parser cannot handle more arguments\n"); + "Parser cannot handle more arguments"); if (!what) xtables_error(PARAMETER_PROBLEM, - "Trying to store NULL argument\n"); + "Trying to store NULL argument"); store->argv[store->argc] = xtables_strdup(what); store->argvattr[store->argc] = quoted; @@ -900,8 +900,7 @@ static char cmd2char(int option) ; if (i >= ARRAY_SIZE(cmdflags)) xtables_error(OTHER_PROBLEM, - "cmd2char(): Invalid command number %u.\n", - 1 << i); + "cmd2char(): Invalid command number %u.", 1 << i); return cmdflags[i]; } @@ -911,8 +910,8 @@ static void add_command(unsigned int *cmd, const int newcmd, if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag"); if (*cmd & (~othercmds)) - xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n", - cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); + xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c", + cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); *cmd |= newcmd; } @@ -979,9 +978,8 @@ static void generic_opt_check(int command, int options) if (!(options & (1<program_name); else if (table_set) xtables_error(PARAMETER_PROBLEM, diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index c9d4ffbf..abe56374 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -115,14 +115,14 @@ static void xtables_restore_parse_line(struct nft_handle *h, 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); + "%s: line %u table name invalid", + xt_params->program_name, line); state->curtable = nft_table_builtin_find(h, table); if (!state->curtable) xtables_error(PARAMETER_PROBLEM, - "%s: line %u table name '%s' invalid\n", - xt_params->program_name, line, table); + "%s: line %u table name '%s' invalid", + xt_params->program_name, line, table); if (p->tablename && (strcmp(p->tablename, table) != 0)) return; @@ -152,8 +152,8 @@ static void xtables_restore_parse_line(struct nft_handle *h, 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); + "%s: line %u chain name invalid", + xt_params->program_name, line); xtables_announce_chain(chain); assert_valid_chain_name(chain); @@ -162,8 +162,8 @@ static void xtables_restore_parse_line(struct nft_handle *h, 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); + "%s: line %u policy invalid", + xt_params->program_name, line); if (nft_chain_builtin_find(state->curtable, chain)) { if (counters) { @@ -172,15 +172,15 @@ static void xtables_restore_parse_line(struct nft_handle *h, if (!ctrs || !parse_counters(ctrs, &count)) xtables_error(PARAMETER_PROBLEM, - "invalid policy counters for chain '%s'\n", - chain); + "invalid policy counters for chain '%s'", + chain); } if (cb->chain_set && cb->chain_set(h, state->curtable->name, chain, policy, &count) < 0) { xtables_error(OTHER_PROBLEM, - "Can't set policy `%s' on `%s' line %u: %s\n", + "Can't set policy `%s' on `%s' line %u: %s", policy, chain, line, strerror(errno)); } @@ -189,13 +189,13 @@ static void xtables_restore_parse_line(struct nft_handle *h, } else if (cb->chain_restore(h, chain, state->curtable->name) < 0 && errno != EEXIST) { xtables_error(PARAMETER_PROBLEM, - "cannot create chain '%s' (%s)\n", + "cannot create chain '%s' (%s)", chain, strerror(errno)); } else if (h->family == NFPROTO_BRIDGE && !ebt_cmd_user_chain_policy(h, state->curtable->name, chain, policy)) { xtables_error(OTHER_PROBLEM, - "Can't set policy `%s' on `%s' line %u: %s\n", + "Can't set policy `%s' on `%s' line %u: %s", policy, chain, line, strerror(errno)); } diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c index 8174a560..b16bbfbe 100644 --- a/libxtables/xtoptions.c +++ b/libxtables/xtoptions.c @@ -924,7 +924,7 @@ void xtables_option_tpcall(unsigned int c, char **argv, bool invert, cb.entry = xtables_option_lookup(t->x6_options, c); if (cb.entry == NULL) xtables_error(OTHER_PROBLEM, - "Extension does not know id %u\n", c); + "Extension does not know id %u", c); cb.arg = optarg; cb.invert = invert; cb.ext_name = t->name; @@ -960,7 +960,7 @@ void xtables_option_mpcall(unsigned int c, char **argv, bool invert, cb.entry = xtables_option_lookup(m->x6_options, c); if (cb.entry == NULL) xtables_error(OTHER_PROBLEM, - "Extension does not know id %u\n", c); + "Extension does not know id %u", c); cb.arg = optarg; cb.invert = invert; cb.ext_name = m->name; -- cgit v1.2.3 From 459a39d9546e4886a725e0b6a17902b73e145b9f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 14 Nov 2022 17:54:42 +0100 Subject: nft: replace nftnl_.*_nlmsg_build_hdr() by nftnl_nlmsg_build_hdr() Replace alias to real nftnl_nlmsg_build_hdr() function call. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 16 ++++++++-------- iptables/nft.c | 12 ++++++------ iptables/xtables-monitor.c | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 2403508c..76e99adc 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -142,8 +142,8 @@ static int fetch_table_cache(struct nft_handle *h) char buf[16536]; int i, ret; - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, - NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, + NLM_F_DUMP, h->seq); ret = mnl_talk(h, nlh, nftnl_table_list_cb, h); if (ret < 0 && errno == EINTR) @@ -454,8 +454,8 @@ static int fetch_set_cache(struct nft_handle *h, } } - nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, - h->family, flags, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, + h->family, flags, h->seq); if (s) { nftnl_set_nlmsg_build_payload(nlh, s); @@ -497,8 +497,8 @@ static int __fetch_chain_cache(struct nft_handle *h, struct nlmsghdr *nlh; int ret; - nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, - c ? NLM_F_ACK : NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, + c ? NLM_F_ACK : NLM_F_DUMP, h->seq); if (c) nftnl_chain_nlmsg_build_payload(nlh, c); @@ -592,8 +592,8 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) 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); + nlh = nftnl_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, &rld); diff --git a/iptables/nft.c b/iptables/nft.c index b65da371..4c0110bb 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2891,8 +2891,8 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_table_nlmsg_build_payload(nlh, table); nft_table_print_debug(h, table, nlh); } @@ -2936,8 +2936,8 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_chain_nlmsg_build_payload(nlh, chain); nft_chain_print_debug(h, chain, nlh); } @@ -2948,8 +2948,8 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_rule_nlmsg_build_payload(nlh, rule); nft_rule_print_debug(h, rule, nlh); } diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index a1eba2f4..cf2729d8 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -227,7 +227,7 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args) exit(EXIT_FAILURE); } - nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain); -- cgit v1.2.3 From 15f43c4be9506bd038bf7d960c0f372f4bd2135e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 14 Nov 2022 17:57:15 +0100 Subject: nft-shared: replace nftnl_expr_get_data() by nftnl_expr_get() Replace nftnl_expr_get_data() alias by real function call. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index e5e3ac0b..97512e3f 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1025,7 +1025,7 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) const void *imm_data; uint32_t len; - imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len); + imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len); dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); if (!dreg) return; -- cgit v1.2.3 From c9d41cefbe6eafb4a6b12c69fc1fa54b716d6c99 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 16 Nov 2022 11:52:20 +0100 Subject: extensions: mark: Test double bitwise in a rule In v1.8.8, the second bitwise changed the first one, messing iptables-nft-save output. Signed-off-by: Phil Sutter --- extensions/libxt_mark.t | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t index 7aeb8715..12c05865 100644 --- a/extensions/libxt_mark.t +++ b/extensions/libxt_mark.t @@ -5,3 +5,4 @@ -m mark --mark 4294967296;;FAIL -m mark --mark -1;;FAIL -m mark;;FAIL +-s 1.2.0.0/15 -m mark --mark 0x0/0xff0;=;OK -- cgit v1.2.3 From 25883ce88bfba087ef142cb909d59dbbc1818b32 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 18 Nov 2022 15:20:32 +0100 Subject: nft: check for unknown meta keys Set ->errmsg when the meta key isn't supported by iptables-nft instead of pretending everything is fine. The old code is good enough to handle rules added by iptables-nft, but its not enough to handle rules added by native nft. At least make sure that there is a an error message telling that iptables-nft could not decode the entire ruleset. Signed-off-by: Florian Westphal --- iptables/nft-arp.c | 9 ++++++--- iptables/nft-bridge.c | 6 +++++- iptables/nft-ipv4.c | 7 +++++-- iptables/nft-ipv6.c | 7 +++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index e9e11141..59f100af 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -168,11 +168,14 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct arpt_entry *fw = &cs->arp; uint8_t flags = 0; - parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, + if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, fw->arp.outiface, fw->arp.outiface_mask, - &flags); + &flags) == 0) { + fw->arp.invflags |= flags; + return; + } - fw->arp.invflags |= flags; + ctx->errmsg = "Unknown arp meta key"; } static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 749cbc6f..e8ac7a36 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -197,7 +197,10 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags); + if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { + ctx->errmsg = "unknown meta key"; + return; + } switch (reg->meta_dreg.key) { case NFT_META_BRI_IIFNAME: @@ -221,6 +224,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, snprintf(fw->out, sizeof(fw->out), "%s", oifname); break; default: + ctx->errmsg = "unknown bridge meta key"; break; } } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 92a914f1..6c62dd46 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -146,9 +146,12 @@ static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, break; } - parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, cs->fw.ip.outiface, cs->fw.ip.outiface_mask, - &cs->fw.ip.invflags); + &cs->fw.ip.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv4 meta key"; } static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 7ca9d842..98c35afa 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -119,9 +119,12 @@ static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, break; } - parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, - cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); + cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv6 meta key"; } static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, -- cgit v1.2.3 From 83241d3f173dd57c3fdc347490213776a070fa40 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 23 Nov 2022 14:44:22 +0100 Subject: iptables-nft: exit nonzero when iptables-save cannot decode all expressions We always return 0, even if we printed some error message half-way. Increment an error counter whenever an error message was printed so that the chain-loop can exit with an error if this counter is nonzero. Another effect is that iptables-save will no longer print the COMMIT line anmore. Reported-by: Phil Sutter Signed-off-by: Florian Westphal Acked-by: Phil Sutter --- iptables/nft-bridge.c | 4 ++-- iptables/nft-shared.c | 10 +++++++--- iptables/nft-shared.h | 4 ++-- iptables/nft.c | 26 ++++++++++++++++++++------ iptables/nft.h | 2 +- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index e8ac7a36..4367d072 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -563,12 +563,12 @@ static void nft_bridge_parse_target(struct xtables_target *t, cs->jumpto = t->name; } -static void nft_rule_to_ebtables_command_state(struct nft_handle *h, +static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { cs->eb.bitmask = EBT_NOPROTO; - nft_rule_to_iptables_command_state(h, r, cs); + return nft_rule_to_iptables_command_state(h, r, cs); } static void print_iface(const char *option, const char *name, bool invert) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 97512e3f..63d25198 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1199,7 +1199,7 @@ static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } } -void nft_rule_to_iptables_command_state(struct nft_handle *h, +bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { @@ -1210,10 +1210,11 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, .h = h, .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), }; + bool ret = true; iter = nftnl_expr_iter_create(r); if (iter == NULL) - return; + return false; ctx.iter = iter; expr = nftnl_expr_iter_next(iter); @@ -1249,6 +1250,7 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, if (ctx.errmsg) { fprintf(stderr, "%s", ctx.errmsg); ctx.errmsg = NULL; + ret = false; } expr = nftnl_expr_iter_next(iter); @@ -1270,7 +1272,7 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, match = xtables_find_match("comment", XTF_TRY_LOAD, &cs->matches); if (match == NULL) - return; + return false; size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; @@ -1287,6 +1289,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, if (!cs->jumpto) cs->jumpto = ""; + + return ret; } void nft_clear_iptables_command_state(struct iptables_command_state *cs) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 3d935d53..e2c3ac7b 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -159,7 +159,7 @@ struct nft_family_ops { void (*parse_target)(struct xtables_target *t, struct iptables_command_state *cs); void (*init_cs)(struct iptables_command_state *cs); - void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, + bool (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); int (*xlate)(const struct iptables_command_state *cs, @@ -213,7 +213,7 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, unsigned char *outiface_mask, uint8_t *invflags); void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); -void nft_rule_to_iptables_command_state(struct nft_handle *h, +bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void nft_clear_iptables_command_state(struct iptables_command_state *cs); diff --git a/iptables/nft.c b/iptables/nft.c index 4c0110bb..67c5877c 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1748,15 +1748,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, return 1; } -void +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format) { const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); struct iptables_command_state cs = {}; struct nft_family_ops *ops = h->ops; + bool ret; - ops->rule_to_cs(h, r, &cs); + ret = ops->rule_to_cs(h, r, &cs); if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS))) printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt, @@ -1777,6 +1778,8 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, if (ops->clear_cs) ops->clear_cs(&cs); + + return ret; } static bool nft_rule_is_policy_rule(struct nftnl_rule *r) @@ -1887,6 +1890,7 @@ int nft_chain_save(struct nft_chain *nc, void *data) struct nft_rule_save_data { struct nft_handle *h; unsigned int format; + unsigned int errors; }; static int nft_rule_save_cb(struct nft_chain *c, void *data) @@ -1901,7 +1905,11 @@ static int nft_rule_save_cb(struct nft_chain *c, void *data) r = nftnl_rule_iter_next(iter); while (r != NULL) { - nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + bool ret = nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + + if (!ret) + d->errors++; + r = nftnl_rule_iter_next(iter); } @@ -1919,6 +1927,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d); + if (ret == 0 && d.errors) + xtables_error(VERSION_PROBLEM, "Cannot decode all rules provided by kernel"); + /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } @@ -2341,15 +2352,18 @@ static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_rule *rule) { struct iptables_command_state _cs = {}, this = {}, *cs = &_cs; - bool ret = false; + bool ret = false, ret_this, ret_that; - h->ops->rule_to_cs(h, r, &this); - h->ops->rule_to_cs(h, rule, cs); + ret_this = h->ops->rule_to_cs(h, r, &this); + ret_that = h->ops->rule_to_cs(h, rule, cs); DEBUGP("comparing with... "); #ifdef DEBUG_DEL nft_rule_print_save(h, r, NFT_RULE_APPEND, 0); #endif + if (!ret_this || !ret_that) + DEBUGP("Cannot convert rules: %d %d\n", ret_this, ret_that); + if (!h->ops->is_same(cs, &this)) goto out; diff --git a/iptables/nft.h b/iptables/nft.h index 68b0910c..caff1fde 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -203,7 +203,7 @@ enum nft_rule_print { NFT_RULE_DEL, }; -void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format); uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); -- cgit v1.2.3 From c6d7a1dd72a21e7f8f117eedb61bff5b94ef5f0c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 23 Nov 2022 03:35:34 +0100 Subject: extensions: libebt_mark: Fix mark target xlate Target value is constructed setting all non-target bits to one instead of zero. Fixes: 03ecffe6c2cc0 ("ebtables-compat: add initial translations") Signed-off-by: Phil Sutter --- extensions/libebt_mark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c index 423c5c91..40e49618 100644 --- a/extensions/libebt_mark.c +++ b/extensions/libebt_mark.c @@ -201,7 +201,7 @@ static int brmark_xlate(struct xt_xlate *xl, return 0; } - tmp = info->target & EBT_VERDICT_BITS; + tmp = info->target | ~EBT_VERDICT_BITS; xt_xlate_add(xl, "0x%lx %s ", info->mark, brmark_verdict(tmp)); return 1; } -- cgit v1.2.3 From bc5f9d05dbf7d0a6c5256c63c492273c93ad3434 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 11 Mar 2022 18:28:49 +0100 Subject: extensions: libebt_mark: Fix xlate test case The false suffix effectively disabled this test file, but it also has problems: Apart from brmark_xlate() printing 'meta mark' instead of just 'mark', target is printed in the wrong position (like with any other target-possessing extension. Fixes: e67c08880961f ("ebtables-translate: add initial test cases") Signed-off-by: Phil Sutter --- extensions/libebt_mark.txlate | 11 +++++++++++ extensions/libebt_mark.xlate | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 extensions/libebt_mark.txlate delete mode 100644 extensions/libebt_mark.xlate diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate new file mode 100644 index 00000000..7529302d --- /dev/null +++ b/extensions/libebt_mark.txlate @@ -0,0 +1,11 @@ +ebtables-translate -A INPUT --mark-set 42 +nft add rule bridge filter INPUT meta mark set 0x2a accept counter + +ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN +nft add rule bridge filter INPUT meta mark set meta mark or 0x2a return counter + +ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT +nft add rule bridge filter INPUT meta mark set meta mark and 0x2a accept counter + +ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP +nft add rule bridge filter INPUT meta mark set meta mark xor 0x2a drop counter diff --git a/extensions/libebt_mark.xlate b/extensions/libebt_mark.xlate deleted file mode 100644 index e0982a1e..00000000 --- a/extensions/libebt_mark.xlate +++ /dev/null @@ -1,11 +0,0 @@ -ebtables-translate -A INPUT --mark-set 42 -nft add rule bridge filter INPUT mark set 0x2a counter - -ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN -nft add rule bridge filter INPUT mark set mark or 0x2a counter return - -ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT -nft add rule bridge filter INPUT mark set mark and 0x2a counter accept - -ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP -nft add rule bridge filter INPUT mark set mark xor 0x2a counter drop -- cgit v1.2.3 From 8543b6f2f4a3a15a5ece7dd1b320b477ce36a8d5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 16 Nov 2022 13:03:05 +0100 Subject: extensions: libebt_redirect: Fix xlate return code The callback is supposed to return 1 on success, not 0. Fixes: 24ce7465056ae ("ebtables-compat: add redirect match extension") Signed-off-by: Phil Sutter --- extensions/libebt_redirect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c index 6e653997..4d4c7a02 100644 --- a/extensions/libebt_redirect.c +++ b/extensions/libebt_redirect.c @@ -86,7 +86,7 @@ static int brredir_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "meta set pkttype host"); if (red->target != EBT_ACCEPT) xt_xlate_add(xl, " %s ", brredir_verdict(red->target)); - return 0; + return 1; } static struct xtables_target brredirect_target = { -- cgit v1.2.3 From 800bed28b2b7bbd931166c7426640ae619f03342 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 16 Nov 2022 13:09:16 +0100 Subject: extensions: libipt_ttl: Sanitize xlate callback Catch unexpected values in info->mode, also fix indenting. Fixes: 1b320a1a1dc1f ("extensions: libipt_ttl: Add translation to nft") Signed-off-by: Phil Sutter --- extensions/libipt_ttl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c index 6bdd2196..86ba554e 100644 --- a/extensions/libipt_ttl.c +++ b/extensions/libipt_ttl.c @@ -106,7 +106,7 @@ static int ttl_xlate(struct xt_xlate *xl, const struct ipt_ttl_info *info = (struct ipt_ttl_info *) params->match->data; - switch (info->mode) { + switch (info->mode) { case IPT_TTL_EQ: xt_xlate_add(xl, "ip ttl"); break; @@ -121,7 +121,7 @@ static int ttl_xlate(struct xt_xlate *xl, break; default: /* Should not happen. */ - break; + return 0; } xt_xlate_add(xl, " %u", info->ttl); -- cgit v1.2.3 From e6747f6b1098b2bc7dfd482f287b3f90b351f164 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 15:30:11 +0100 Subject: extensions: CONNMARK: Fix xlate callback Bail out if nfmask != ctmask with XT_CONNMARK_SAVE and XT_CONNMARK_RESTORE. Looks like this needs a similar implementation to the one for XT_CONNMARK_SET. Fix shift mark translation: xt_connmark_shift_ops does not contain useful strings for nftables. Also add needed braces around the term being shifted. Fixes: db7b4e0de960c ("extensions: libxt_CONNMARK: Support bit-shifting for --restore,set and save-mark") Signed-off-by: Phil Sutter --- extensions/libxt_CONNMARK.c | 15 ++++++++++----- extensions/libxt_CONNMARK.txlate | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c index 21e10913..a6568c99 100644 --- a/extensions/libxt_CONNMARK.c +++ b/extensions/libxt_CONNMARK.c @@ -595,11 +595,11 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl, { const struct xt_connmark_tginfo2 *info = (const void *)params->target->data; - const char *shift_op = xt_connmark_shift_ops[info->shift_dir]; + const char *braces = info->shift_bits ? "( " : ""; switch (info->mode) { case XT_CONNMARK_SET: - xt_xlate_add(xl, "ct mark set "); + xt_xlate_add(xl, "ct mark set %s", braces); if (info->ctmask == 0xFFFFFFFFU) xt_xlate_add(xl, "0x%x ", info->ctmark); else if (info->ctmark == 0) @@ -615,26 +615,31 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl, info->ctmark, ~info->ctmask); break; case XT_CONNMARK_SAVE: - xt_xlate_add(xl, "ct mark set mark"); + xt_xlate_add(xl, "ct mark set %smark", braces); if (!(info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)) { if (info->nfmask == info->ctmask) xt_xlate_add(xl, " and 0x%x", info->nfmask); + else + return 0; } break; case XT_CONNMARK_RESTORE: - xt_xlate_add(xl, "meta mark set ct mark"); + xt_xlate_add(xl, "meta mark set %sct mark", braces); if (!(info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)) { if (info->nfmask == info->ctmask) xt_xlate_add(xl, " and 0x%x", info->nfmask); + else + return 0; } break; } if (info->mode <= XT_CONNMARK_RESTORE && info->shift_bits != 0) { - xt_xlate_add(xl, " %s %u", shift_op, info->shift_bits); + xt_xlate_add(xl, " ) %s %u", + info->shift_dir ? ">>" : "<<", info->shift_bits); } return 1; diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate index ce40ae5e..99627c2b 100644 --- a/extensions/libxt_CONNMARK.txlate +++ b/extensions/libxt_CONNMARK.txlate @@ -18,3 +18,6 @@ nft add rule ip mangle PREROUTING counter ct mark set mark iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark nft add rule ip mangle PREROUTING counter meta mark set ct mark + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x23/0x42 --right-shift-mark 5 +nft add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5 -- cgit v1.2.3 From c4fc6440a6f39606e38744bfc827852bb68829f4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 16:01:11 +0100 Subject: extensions: MARK: Sanitize MARK_xlate() Since markinfo->mode might contain unexpected values, add a default case returning zero. Fixes: afefc7a134ca0 ("extensions: libxt_MARK: Add translation for revision 1 to nft") Signed-off-by: Phil Sutter --- extensions/libxt_MARK.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index 1536563d..100f6a38 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -366,6 +366,8 @@ static int MARK_xlate(struct xt_xlate *xl, case XT_MARK_OR: xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark); break; + default: + return 0; } return 1; -- cgit v1.2.3 From e05d9af176cb2a62c1bd24fa1d82b12a8ad00221 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 16:06:46 +0100 Subject: extensions: TCPMSS: Use xlate callback for IPv6, too Data structures are identical and the translation is layer3-agnostic. Fixes: bebce197adb42 ("iptables: iptables-compat translation for TCPMSS") Signed-off-by: Phil Sutter --- extensions/libxt_TCPMSS.c | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c index 0d9b200e..251a5532 100644 --- a/extensions/libxt_TCPMSS.c +++ b/extensions/libxt_TCPMSS.c @@ -131,6 +131,7 @@ static struct xtables_target tcpmss_tg_reg[] = { .x6_parse = TCPMSS_parse, .x6_fcheck = TCPMSS_check, .x6_options = TCPMSS6_opts, + .xlate = TCPMSS_xlate, }, }; -- cgit v1.2.3 From 161fb8ad126d8f330c8f59a4a1b5885d26477664 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 16:10:14 +0100 Subject: extensions: TOS: Fix v1 xlate callback Translation entirely ignored tos_mask field. Fixes: b669e18489709 ("extensions: libxt_TOS: Add translation to nft") Signed-off-by: Phil Sutter --- extensions/libxt_TOS.c | 33 +++++++++++++++++++++++---------- extensions/libxt_TOS.txlate | 9 ++++++--- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c index b66fa329..4fc849bd 100644 --- a/extensions/libxt_TOS.c +++ b/extensions/libxt_TOS.c @@ -183,28 +183,41 @@ static void tos_tg_save(const void *ip, const struct xt_entry_target *target) printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask); } +static int __tos_xlate(struct xt_xlate *xl, const char *ip, + uint8_t tos, uint8_t tosmask) +{ + xt_xlate_add(xl, "%s dscp set ", ip); + if ((tosmask & 0x3f) == 0x3f) + xt_xlate_add(xl, "0x%02x", tos >> 2); + else if (!tos) + xt_xlate_add(xl, "%s dscp and 0x%02x", + ip, (uint8_t)~tosmask >> 2); + else if (tos == tosmask) + xt_xlate_add(xl, "%s dscp or 0x%02x", ip, tos >> 2); + else if (!tosmask) + xt_xlate_add(xl, "%s dscp xor 0x%02x", ip, tos >> 2); + else + xt_xlate_add(xl, "%s dscp and 0x%02x xor 0x%02x", + ip, (uint8_t)~tosmask >> 2, tos >> 2); + return 1; +} + static int tos_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { const struct ipt_tos_target_info *info = (struct ipt_tos_target_info *) params->target->data; - uint8_t dscp = info->tos >> 2; - - xt_xlate_add(xl, "ip dscp set 0x%02x", dscp); - return 1; + return __tos_xlate(xl, "ip", info->tos, UINT8_MAX); } static int tos_xlate6(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct ipt_tos_target_info *info = - (struct ipt_tos_target_info *) params->target->data; - uint8_t dscp = info->tos >> 2; + const struct xt_tos_target_info *info = + (struct xt_tos_target_info *)params->target->data; - xt_xlate_add(xl, "ip6 dscp set 0x%02x", dscp); - - return 1; + return __tos_xlate(xl, "ip6", info->tos_value, info->tos_mask); } static struct xtables_target tos_tg_reg[] = { diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate index 0952310e..9c126742 100644 --- a/extensions/libxt_TOS.txlate +++ b/extensions/libxt_TOS.txlate @@ -14,10 +14,13 @@ ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 ip6tables-translate -A INPUT -j TOS --and-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04 ip6tables-translate -A INPUT -j TOS --or-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04 ip6tables-translate -A INPUT -j TOS --xor-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04 + +ip6tables-translate -A INPUT -j TOS --set-tos 0x12/0x34 +nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04 -- cgit v1.2.3 From 424ef98918d31377a305cdf1626e1c1f69ab6df1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 16:37:02 +0100 Subject: extensions: ecn: Sanitize xlate callback Catch unexpected values in einfo->ip_ect. Fixes: ca42442093d3d ("iptables: extensions: libxt_ecn: Add translation to nft") Signed-off-by: Phil Sutter --- extensions/libxt_ecn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/libxt_ecn.c b/extensions/libxt_ecn.c index ad3c7a03..83a4acfa 100644 --- a/extensions/libxt_ecn.c +++ b/extensions/libxt_ecn.c @@ -156,6 +156,8 @@ static int ecn_xlate(struct xt_xlate *xl, case 3: xt_xlate_add(xl, "ce"); break; + default: + return 0; } } return 1; -- cgit v1.2.3 From 0b946dabf34a068adf3e35924578ffb06a249bb8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 16:39:40 +0100 Subject: extensions: tcp: Translate TCP option match A simple task since 'tcp option' expression exists. Signed-off-by: Phil Sutter --- extensions/libxt_tcp.c | 9 ++++++--- extensions/libxt_tcp.txlate | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 0b115cdd..043382d4 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -430,9 +430,12 @@ static int tcp_xlate(struct xt_xlate *xl, space = " "; } - /* XXX not yet implemented */ - if (tcpinfo->option || (tcpinfo->invflags & XT_TCP_INV_OPTION)) - return 0; + if (tcpinfo->option) { + xt_xlate_add(xl, "%stcp option %u %s", space, tcpinfo->option, + tcpinfo->invflags & XT_TCP_INV_OPTION ? + "missing" : "exists"); + space = " "; + } if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { xt_xlate_add(xl, "%stcp flags %s", space, diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate index 921d4af0..a1f0e909 100644 --- a/extensions/libxt_tcp.txlate +++ b/extensions/libxt_tcp.txlate @@ -24,3 +24,9 @@ nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter iptables-translate -A INPUT ! -f -p tcp --dport 22 nft add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter + +iptables-translate -A INPUT -p tcp --tcp-option 23 +nft add rule ip filter INPUT tcp option 23 exists counter + +iptables-translate -A INPUT -p tcp ! --tcp-option 23 +nft add rule ip filter INPUT tcp option 23 missing counter -- cgit v1.2.3 From 06f0d6fdb73be00570604b33c00b1f7bf1dacaa5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 17:37:27 +0100 Subject: extensions: libebt_log: Add comment to clarify xlate callback Several log flags are ignored by the function. Add a comment explaining why this is correct. Signed-off-by: Phil Sutter --- extensions/libebt_log.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 47708d79..13c7fafe 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -191,6 +191,8 @@ static int brlog_xlate(struct xt_xlate *xl, if (loginfo->loglevel != LOG_DEFAULT_LEVEL) xt_xlate_add(xl, " level %s", eight_priority[loginfo->loglevel].c_name); + /* ebt_log always decodes MAC header, nft_log always decodes upper header - + * so set flags ether and ignore EBT_LOG_IP, EBT_LOG_ARP and EBT_LOG_IP6 */ xt_xlate_add(xl, " flags ether "); return 1; -- cgit v1.2.3 From 8a714a4f4173d6e3d32ff414fac837bc0fd6b99c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 17 Nov 2022 17:38:52 +0100 Subject: extensions: frag: Add comment to clarify xlate callback Matching on fragmentation header length is ineffective in kernel, xlate callback correctly ignores it. Add a comment as a hint for reviewers. Signed-off-by: Phil Sutter --- extensions/libip6t_frag.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c index 3842496e..72a43153 100644 --- a/extensions/libip6t_frag.c +++ b/extensions/libip6t_frag.c @@ -193,6 +193,8 @@ static int frag_xlate(struct xt_xlate *xl, space = " "; } + /* ignore ineffective IP6T_FRAG_LEN bit */ + if (fraginfo->flags & IP6T_FRAG_RES) { xt_xlate_add(xl, "%sfrag reserved 1", space); space = " "; -- cgit v1.2.3 From 208290ff0bfecb49044c3df87149aa6fa683de09 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Mar 2022 11:58:37 +0100 Subject: extensions: ipcomp: Add comment to clarify xlate callback Kernel ignores 'hdrres' field, this matching on reserved field value was never effective. While being at it, drop its description from man page. Continue to parse and print it for compatibility reasons, but avoid attracting new users. Signed-off-by: Phil Sutter --- extensions/libxt_ipcomp.c | 2 ++ extensions/libxt_ipcomp.c.man | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/libxt_ipcomp.c b/extensions/libxt_ipcomp.c index b5c43128..4171c4a1 100644 --- a/extensions/libxt_ipcomp.c +++ b/extensions/libxt_ipcomp.c @@ -101,6 +101,8 @@ static int comp_xlate(struct xt_xlate *xl, const struct xt_ipcomp *compinfo = (struct xt_ipcomp *)params->match->data; + /* ignore compinfo->hdrres like kernel's xt_ipcomp.c does */ + xt_xlate_add(xl, "comp cpi %s", compinfo->invflags & XT_IPCOMP_INV_SPI ? "!= " : ""); if (compinfo->spis[0] != compinfo->spis[1]) diff --git a/extensions/libxt_ipcomp.c.man b/extensions/libxt_ipcomp.c.man index f3b17d21..824f5b3d 100644 --- a/extensions/libxt_ipcomp.c.man +++ b/extensions/libxt_ipcomp.c.man @@ -2,6 +2,3 @@ This module matches the parameters in IPcomp header of IPsec packets. .TP [\fB!\fP] \fB\-\-ipcompspi\fP \fIspi\fP[\fB:\fP\fIspi\fP] Matches IPcomp header CPI value. -.TP -\fB\-\-compres\fP -Matches if the reserved field is filled with zero. -- cgit v1.2.3 From 023dd2c515be63ddb2f0b6a6f3bccab4cdf7a71c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 03:13:14 +0100 Subject: libxtables: xt_xlate_add() to take care of spacing Try to eliminate most of the whitespace issues by separating strings from separate xt_xlate_add() calls by whitespace if needed. Cover the common case of consecutive range, list or MAC/IP address printing by inserting whitespace only if the string to be appended starts with an alphanumeric character or a brace. The latter helps to make spacing in anonymous sets consistent. Provide *_nospc() variants which disable the auto-spacing for the mandatory exception to the rule. Make things round by dropping any trailing whitespace before returning the buffer via xt_xlate_get(). Signed-off-by: Phil Sutter --- extensions/libxt_dccp.txlate | 2 +- extensions/libxt_hashlimit.c | 2 +- extensions/libxt_hashlimit.txlate | 4 +-- extensions/libxt_multiport.txlate | 2 +- extensions/libxt_tcp.c | 7 ++--- extensions/libxt_time.txlate | 6 ++-- include/xtables.h | 3 ++ libxtables/xtables.c | 58 +++++++++++++++++++++++++++++++++++---- 8 files changed, 66 insertions(+), 18 deletions(-) diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate index ea853f6a..be950bcb 100644 --- a/extensions/libxt_dccp.txlate +++ b/extensions/libxt_dccp.txlate @@ -14,7 +14,7 @@ iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID nft add rule ip filter INPUT dccp type 10-15 counter iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID -nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter +nft add rule ip filter INPUT dccp dport 100 dccp type { request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15 } counter iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100 nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c index 93ee1c32..24e784ab 100644 --- a/extensions/libxt_hashlimit.c +++ b/extensions/libxt_hashlimit.c @@ -1270,7 +1270,7 @@ static void hashlimit_print_subnet_xlate(struct xt_xlate *xl, } } - xt_xlate_add(xl, fmt, acm); + xt_xlate_add_nospc(xl, fmt, acm); if (nblocks > 0) xt_xlate_add(xl, "%c", sep); } diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate index 6c8d07f1..251a30d3 100644 --- a/extensions/libxt_hashlimit.txlate +++ b/extensions/libxt_hashlimit.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes} ct state new counter drop +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets} ct state new counter drop +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate index bced1b84..bf015265 100644 --- a/extensions/libxt_multiport.txlate +++ b/extensions/libxt_multiport.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81} counter accept +nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81 } counter accept iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 043382d4..2ef84299 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -380,10 +380,9 @@ static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags) for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++); - if (have_flag) - xt_xlate_add(xl, ","); - - xt_xlate_add(xl, "%s", tcp_flag_names_xlate[i].name); + xt_xlate_add(xl, "%s%s", + have_flag ? "," : "", + tcp_flag_names_xlate[i].name); have_flag = 1; flags &= ~tcp_flag_names_xlate[i].flag; diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate index ff4a7b88..2083ab94 100644 --- a/extensions/libxt_time.txlate +++ b/extensions/libxt_time.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta day {6,0} counter reject +nft add rule ip filter INPUT icmp type echo-request meta day { 6,0 } counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject @@ -20,7 +20,7 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {1,2,3,4,5} counter reject +nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1,2,3,4,5 } counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {6,0} counter reject +nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6,0 } counter reject diff --git a/include/xtables.h b/include/xtables.h index 9eba4f61..dad1949e 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -621,8 +621,11 @@ extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); struct xt_xlate *xt_xlate_alloc(int size); void xt_xlate_free(struct xt_xlate *xl); void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); +void xt_xlate_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); #define xt_xlate_rule_add xt_xlate_add +#define xt_xlate_rule_add_nospc xt_xlate_add_nospc void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); +void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment); const char *xt_xlate_get_comment(struct xt_xlate *xl); void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family); diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 479dbae0..e3e444ac 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -2490,16 +2490,39 @@ void xt_xlate_free(struct xt_xlate *xl) free(xl); } +static bool isbrace(char c) +{ + switch (c) { + case '(': + case ')': + case '{': + case '}': + case '[': + case ']': + return true; + } + return false; +} + static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type, - const char *fmt, va_list ap) + bool space, const char *fmt, va_list ap) { struct xt_xlate_buf *buf = &xl->buf[type]; + char tmpbuf[1024] = ""; int len; - len = vsnprintf(buf->data + buf->off, buf->rem, fmt, ap); - if (len < 0 || len >= buf->rem) + len = vsnprintf(tmpbuf, 1024, fmt, ap); + if (len < 0 || len >= buf->rem - 1) xtables_error(RESOURCE_PROBLEM, "OOM"); + if (space && buf->off && + !isspace(buf->data[buf->off - 1]) && + (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) { + buf->data[buf->off] = ' '; + buf->off++; + buf->rem--; + } + sprintf(buf->data + buf->off, "%s", tmpbuf); buf->rem -= len; buf->off += len; } @@ -2509,7 +2532,16 @@ void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...) va_list ap; va_start(ap, fmt); - __xt_xlate_add(xl, XT_XLATE_RULE, fmt, ap); + __xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap); + va_end(ap); +} + +void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + __xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap); va_end(ap); } @@ -2518,7 +2550,16 @@ void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) va_list ap; va_start(ap, fmt); - __xt_xlate_add(xl, XT_XLATE_SET, fmt, ap); + __xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap); + va_end(ap); +} + +void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + __xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap); va_end(ap); } @@ -2545,7 +2586,12 @@ uint8_t xt_xlate_get_family(struct xt_xlate *xl) const char *xt_xlate_get(struct xt_xlate *xl) { - return xl->buf[XT_XLATE_RULE].data; + struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE]; + + while (buf->off && isspace(buf->data[buf->off - 1])) + buf->data[--buf->off] = '\0'; + + return buf->data; } const char *xt_xlate_set_get(struct xt_xlate *xl) -- cgit v1.2.3 From 7533e96dadfcecbb49f819976ffc986a67920545 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 04:27:21 +0100 Subject: extensions: Leverage xlate auto-spacing Drop code which is used explicitly to deal with spacing. Signed-off-by: Phil Sutter --- extensions/libip6t_frag.c | 28 +++++++++++----------------- extensions/libip6t_rt.c | 7 ++----- extensions/libxt_dccp.c | 11 ++--------- extensions/libxt_devgroup.c | 4 +--- extensions/libxt_iprange.c | 12 +++--------- extensions/libxt_sctp.c | 32 +++++++++++++------------------- extensions/libxt_tcp.c | 15 +++++---------- extensions/libxt_time.txlate | 6 +++--- extensions/libxt_udp.c | 6 ++---- iptables/nft-bridge.c | 3 --- iptables/xtables-translate.c | 5 ----- 11 files changed, 42 insertions(+), 87 deletions(-) diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c index 72a43153..49c787e7 100644 --- a/extensions/libip6t_frag.c +++ b/extensions/libip6t_frag.c @@ -178,7 +178,6 @@ static int frag_xlate(struct xt_xlate *xl, { const struct ip6t_frag *fraginfo = (struct ip6t_frag *)params->match->data; - char *space= ""; if (!(fraginfo->ids[0] == 0 && fraginfo->ids[1] == 0xFFFFFFFF)) { xt_xlate_add(xl, "frag id %s", @@ -190,26 +189,21 @@ static int frag_xlate(struct xt_xlate *xl, else xt_xlate_add(xl, "%u", fraginfo->ids[0]); - space = " "; } /* ignore ineffective IP6T_FRAG_LEN bit */ - if (fraginfo->flags & IP6T_FRAG_RES) { - xt_xlate_add(xl, "%sfrag reserved 1", space); - space = " "; - } - if (fraginfo->flags & IP6T_FRAG_FST) { - xt_xlate_add(xl, "%sfrag frag-off 0", space); - space = " "; - } - if (fraginfo->flags & IP6T_FRAG_MF) { - xt_xlate_add(xl, "%sfrag more-fragments 1", space); - space = " "; - } - if (fraginfo->flags & IP6T_FRAG_NMF) { - xt_xlate_add(xl, "%sfrag more-fragments 0", space); - } + if (fraginfo->flags & IP6T_FRAG_RES) + xt_xlate_add(xl, "frag reserved 1"); + + if (fraginfo->flags & IP6T_FRAG_FST) + xt_xlate_add(xl, "frag frag-off 0"); + + if (fraginfo->flags & IP6T_FRAG_MF) + xt_xlate_add(xl, "frag more-fragments 1"); + + if (fraginfo->flags & IP6T_FRAG_NMF) + xt_xlate_add(xl, "frag more-fragments 0"); return 1; } diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c index 9708b5a0..d5b0458b 100644 --- a/extensions/libip6t_rt.c +++ b/extensions/libip6t_rt.c @@ -248,17 +248,15 @@ static int rt_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { const struct ip6t_rt *rtinfo = (struct ip6t_rt *)params->match->data; - char *space = ""; if (rtinfo->flags & IP6T_RT_TYP) { xt_xlate_add(xl, "rt type%s %u", (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !=" : "", rtinfo->rt_type); - space = " "; } if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { - xt_xlate_add(xl, "%srt seg-left%s ", space, + xt_xlate_add(xl, "rt seg-left%s ", (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : ""); if (rtinfo->segsleft[0] != rtinfo->segsleft[1]) @@ -266,11 +264,10 @@ static int rt_xlate(struct xt_xlate *xl, rtinfo->segsleft[1]); else xt_xlate_add(xl, "%u", rtinfo->segsleft[0]); - space = " "; } if (rtinfo->flags & IP6T_RT_LEN) { - xt_xlate_add(xl, "%srt hdrlength%s %u", space, + xt_xlate_add(xl, "rt hdrlength%s %u", (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "", rtinfo->hdrlen); } diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c index abd420fc..bfceced3 100644 --- a/extensions/libxt_dccp.c +++ b/extensions/libxt_dccp.c @@ -343,7 +343,6 @@ static int dccp_xlate(struct xt_xlate *xl, { const struct xt_dccp_info *einfo = (const struct xt_dccp_info *)params->match->data; - char *space = ""; int ret = 1; if (einfo->flags & XT_DCCP_SRC_PORTS) { @@ -353,27 +352,21 @@ static int dccp_xlate(struct xt_xlate *xl, if (einfo->spts[0] != einfo->spts[1]) xt_xlate_add(xl, "-%u", einfo->spts[1]); - - space = " "; } if (einfo->flags & XT_DCCP_DEST_PORTS) { - xt_xlate_add(xl, "%sdccp dport%s %u", space, + xt_xlate_add(xl, "dccp dport%s %u", einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); if (einfo->dpts[0] != einfo->dpts[1]) xt_xlate_add(xl, "-%u", einfo->dpts[1]); - - space = " "; } if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) { - xt_xlate_add(xl, "%sdccp type%s ", space, + xt_xlate_add(xl, "dccp type%s ", einfo->invflags & XT_DCCP_TYPE ? " !=" : ""); ret = dccp_type_xlate(einfo, xl); - - space = " "; } /* FIXME: no dccp option support in nftables yet */ diff --git a/extensions/libxt_devgroup.c b/extensions/libxt_devgroup.c index a88211c5..f60526ff 100644 --- a/extensions/libxt_devgroup.c +++ b/extensions/libxt_devgroup.c @@ -129,7 +129,6 @@ static void devgroup_show_xlate(const struct xt_devgroup_info *info, struct xt_xlate *xl, int numeric) { enum xt_op op = XT_OP_EQ; - char *space = ""; if (info->flags & XT_DEVGROUP_MATCH_SRC) { if (info->flags & XT_DEVGROUP_INVERT_SRC) @@ -137,13 +136,12 @@ static void devgroup_show_xlate(const struct xt_devgroup_info *info, xt_xlate_add(xl, "iifgroup "); print_devgroup_xlate(info->src_group, op, info->src_mask, xl, numeric); - space = " "; } if (info->flags & XT_DEVGROUP_MATCH_DST) { if (info->flags & XT_DEVGROUP_INVERT_DST) op = XT_OP_NEQ; - xt_xlate_add(xl, "%soifgroup ", space); + xt_xlate_add(xl, "oifgroup "); print_devgroup_xlate(info->dst_group, op, info->dst_mask, xl, numeric); } diff --git a/extensions/libxt_iprange.c b/extensions/libxt_iprange.c index 04ce7b36..0df709d5 100644 --- a/extensions/libxt_iprange.c +++ b/extensions/libxt_iprange.c @@ -317,16 +317,14 @@ static int iprange_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { const struct ipt_iprange_info *info = (const void *)params->match->data; - char *space = ""; if (info->flags & IPRANGE_SRC) { xt_xlate_add(xl, "ip saddr%s", info->flags & IPRANGE_SRC_INV ? " !=" : ""); print_iprange_xlate(&info->src, xl); - space = " "; } if (info->flags & IPRANGE_DST) { - xt_xlate_add(xl, "%sip daddr%s", space, + xt_xlate_add(xl, "ip daddr%s", info->flags & IPRANGE_DST_INV ? " !=" : ""); print_iprange_xlate(&info->dst, xl); } @@ -339,7 +337,6 @@ static int iprange_mt4_xlate(struct xt_xlate *xl, { const struct xt_iprange_mtinfo *info = (const void *)params->match->data; - char *space = ""; if (info->flags & IPRANGE_SRC) { xt_xlate_add(xl, "ip saddr%s %s", @@ -347,10 +344,9 @@ static int iprange_mt4_xlate(struct xt_xlate *xl, xtables_ipaddr_to_numeric(&info->src_min.in)); xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); - space = " "; } if (info->flags & IPRANGE_DST) { - xt_xlate_add(xl, "%sip daddr%s %s", space, + xt_xlate_add(xl, "ip daddr%s %s", info->flags & IPRANGE_DST_INV ? " !=" : "", xtables_ipaddr_to_numeric(&info->dst_min.in)); xt_xlate_add(xl, "-%s", @@ -365,7 +361,6 @@ static int iprange_mt6_xlate(struct xt_xlate *xl, { const struct xt_iprange_mtinfo *info = (const void *)params->match->data; - char *space = ""; if (info->flags & IPRANGE_SRC) { xt_xlate_add(xl, "ip6 saddr%s %s", @@ -373,10 +368,9 @@ static int iprange_mt6_xlate(struct xt_xlate *xl, xtables_ip6addr_to_numeric(&info->src_min.in6)); xt_xlate_add(xl, "-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); - space = " "; } if (info->flags & IPRANGE_DST) { - xt_xlate_add(xl, "%sip6 daddr%s %s", space, + xt_xlate_add(xl, "ip6 daddr%s %s", info->flags & IPRANGE_DST_INV ? " !=" : "", xtables_ip6addr_to_numeric(&info->dst_min.in6)); xt_xlate_add(xl, "-%s", diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index 8f069a43..fe5f5621 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -489,24 +489,24 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match) } } -static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space, - const struct xt_sctp_info *einfo, - const struct sctp_chunk_names *scn) +static void sctp_xlate_chunk(struct xt_xlate *xl, + const struct xt_sctp_info *einfo, + const struct sctp_chunk_names *scn) { bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES; const struct xt_sctp_flag_info *flag_info = NULL; int i; if (!scn->nftname) - return space; + return; if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) { if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY) - return space; + return; - xt_xlate_add(xl, "%ssctp chunk %s %s", space, + xt_xlate_add(xl, "sctp chunk %s %s", scn->nftname, inv ? "exists" : "missing"); - return " "; + return; } for (i = 0; i < einfo->flag_count; i++) { @@ -517,16 +517,14 @@ static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space, } if (!flag_info) { - xt_xlate_add(xl, "%ssctp chunk %s %s", space, + xt_xlate_add(xl, "sctp chunk %s %s", scn->nftname, inv ? "missing" : "exists"); - return " "; + return; } - xt_xlate_add(xl, "%ssctp chunk %s flags & 0x%x %s 0x%x", space, + xt_xlate_add(xl, "sctp chunk %s flags & 0x%x %s 0x%x", scn->nftname, flag_info->flag_mask, inv ? "!=" : "==", flag_info->flag); - - return " "; } static int sctp_xlate(struct xt_xlate *xl, @@ -534,7 +532,6 @@ static int sctp_xlate(struct xt_xlate *xl, { const struct xt_sctp_info *einfo = (const struct xt_sctp_info *)params->match->data; - const char *space = ""; if (!einfo->flags) return 0; @@ -548,19 +545,17 @@ static int sctp_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "sctp sport%s %u", einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "", einfo->spts[0]); - space = " "; } if (einfo->flags & XT_SCTP_DEST_PORTS) { if (einfo->dpts[0] != einfo->dpts[1]) - xt_xlate_add(xl, "%ssctp dport%s %u-%u", space, + xt_xlate_add(xl, "sctp dport%s %u-%u", einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0], einfo->dpts[1]); else - xt_xlate_add(xl, "%ssctp dport%s %u", space, + xt_xlate_add(xl, "sctp dport%s %u", einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); - space = " "; } if (einfo->flags & XT_SCTP_CHUNK_TYPES) { @@ -570,8 +565,7 @@ static int sctp_xlate(struct xt_xlate *xl, return 0; for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++) - space = sctp_xlate_chunk(xl, space, einfo, - &sctp_chunk_names[i]); + sctp_xlate_chunk(xl, einfo, &sctp_chunk_names[i]); } return 1; diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 2ef84299..f8257282 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -397,7 +397,6 @@ static int tcp_xlate(struct xt_xlate *xl, { const struct xt_tcp *tcpinfo = (const struct xt_tcp *)params->match->data; - char *space= ""; if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xffff) { if (tcpinfo->spts[0] != tcpinfo->spts[1]) { @@ -411,33 +410,29 @@ static int tcp_xlate(struct xt_xlate *xl, "!= " : "", tcpinfo->spts[0]); } - space = " "; } if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xffff) { if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) { - xt_xlate_add(xl, "%stcp dport %s%u-%u", space, + xt_xlate_add(xl, "tcp dport %s%u-%u", tcpinfo->invflags & XT_TCP_INV_DSTPT ? "!= " : "", tcpinfo->dpts[0], tcpinfo->dpts[1]); } else { - xt_xlate_add(xl, "%stcp dport %s%u", space, + xt_xlate_add(xl, "tcp dport %s%u", tcpinfo->invflags & XT_TCP_INV_DSTPT ? "!= " : "", tcpinfo->dpts[0]); } - space = " "; } - if (tcpinfo->option) { - xt_xlate_add(xl, "%stcp option %u %s", space, tcpinfo->option, + if (tcpinfo->option) + xt_xlate_add(xl, "tcp option %u %s", tcpinfo->option, tcpinfo->invflags & XT_TCP_INV_OPTION ? "missing" : "exists"); - space = " "; - } if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { - xt_xlate_add(xl, "%stcp flags %s", space, + xt_xlate_add(xl, "tcp flags %s", tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": ""); print_tcp_xlate(xl, tcpinfo->flg_cmp); xt_xlate_add(xl, " / "); diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate index 2083ab94..6aea2aed 100644 --- a/extensions/libxt_time.txlate +++ b/extensions/libxt_time.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta day { 6,0 } counter reject +nft add rule ip filter INPUT icmp type echo-request meta day { 6,0 } counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject +nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject +nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject diff --git a/extensions/libxt_udp.c b/extensions/libxt_udp.c index 0c7a4bc2..ba1c3eb7 100644 --- a/extensions/libxt_udp.c +++ b/extensions/libxt_udp.c @@ -156,7 +156,6 @@ static int udp_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { const struct xt_udp *udpinfo = (struct xt_udp *)params->match->data; - char *space= ""; if (udpinfo->spts[0] != 0 || udpinfo->spts[1] != 0xFFFF) { if (udpinfo->spts[0] != udpinfo->spts[1]) { @@ -170,17 +169,16 @@ static int udp_xlate(struct xt_xlate *xl, "!= ": "", udpinfo->spts[0]); } - space = " "; } if (udpinfo->dpts[0] != 0 || udpinfo->dpts[1] != 0xFFFF) { if (udpinfo->dpts[0] != udpinfo->dpts[1]) { - xt_xlate_add(xl,"%sudp dport %s%u-%u", space, + xt_xlate_add(xl,"udp dport %s%u-%u", udpinfo->invflags & XT_UDP_INV_SRCPT ? "!= ": "", udpinfo->dpts[0], udpinfo->dpts[1]); } else { - xt_xlate_add(xl,"%sudp dport %s%u", space, + xt_xlate_add(xl,"udp dport %s%u", udpinfo->invflags & XT_UDP_INV_SRCPT ? "!= ": "", udpinfo->dpts[0]); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 4367d072..31800913 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -830,7 +830,6 @@ static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xla else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) xt_xlate_add(xl, " return"); else if (cs->target->xlate) { - xt_xlate_add(xl, " "); struct xt_xlate_tg_params params = { .ip = (const void *)&cs->eb, .target = cs->target->t, @@ -876,8 +875,6 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv for (i=1; i < ETH_ALEN; i++) xt_xlate_add(xl, ":%02x", mac[i] & mask[i]); } - - xt_xlate_add(xl, " "); } static int nft_bridge_xlate(const struct iptables_command_state *cs, diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index d1e87f16..4e8db4be 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -83,7 +83,6 @@ int xlate_action(const struct iptables_command_state *cs, bool goto_set, else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) xt_xlate_add(xl, " return"); else if (cs->target->xlate) { - xt_xlate_add(xl, " "); struct xt_xlate_tg_params params = { .ip = (const void *)&cs->fw, .target = cs->target->t, @@ -122,10 +121,6 @@ int xlate_matches(const struct iptables_command_state *cs, struct xt_xlate *xl) return 0; ret = matchp->match->xlate(xl, ¶ms); - - if (strcmp(matchp->match->name, "comment") != 0) - xt_xlate_add(xl, " "); - if (!ret) break; } -- cgit v1.2.3 From 116848ea1e5d8d02fd766356a642bd81574e2723 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 04:35:35 +0100 Subject: extensions: libxt_conntrack: Drop extra whitespace in xlate No point in having this. Interestingly, other test cases even made up for it. Fixes: 0afd957f6bc03 ("extensions: libxt_state: add translation to nft") Signed-off-by: Phil Sutter --- extensions/libxt_SYNPROXY.txlate | 2 +- extensions/libxt_conntrack.c | 1 - extensions/libxt_hashlimit.txlate | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_SYNPROXY.txlate b/extensions/libxt_SYNPROXY.txlate index b3de2b2a..a2a3b6c5 100644 --- a/extensions/libxt_SYNPROXY.txlate +++ b/extensions/libxt_SYNPROXY.txlate @@ -1,2 +1,2 @@ iptables-translate -t mangle -A INPUT -i iifname -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 -nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460 +nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460 diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 08dba42d..09548c29 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1186,7 +1186,6 @@ static int state_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "ct state "); state_xlate_print(xl, sinfo->state_mask, sinfo->invert_flags & XT_CONNTRACK_STATE); - xt_xlate_add(xl, " "); return 1; } diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate index 251a30d3..4cc26868 100644 --- a/extensions/libxt_hashlimit.txlate +++ b/extensions/libxt_hashlimit.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop -- cgit v1.2.3 From dea402e6fc2372813d1545303ded73f546bca3c2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 14:05:28 +0100 Subject: extensions: xlate: Format sets consistently Print a space after separating commas. Signed-off-by: Phil Sutter --- extensions/libxt_multiport.c | 4 ++-- extensions/libxt_multiport.txlate | 2 +- extensions/libxt_time.c | 12 ++++-------- extensions/libxt_time.txlate | 6 +++--- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c index 6b0c8190..f3136d8a 100644 --- a/extensions/libxt_multiport.c +++ b/extensions/libxt_multiport.c @@ -497,7 +497,7 @@ static int __multiport_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "{ "); for (i = 0; i < multiinfo->count; i++) - xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]); + xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]); if (multiinfo->count > 1) xt_xlate_add(xl, "}"); @@ -560,7 +560,7 @@ static int __multiport_xlate_v1(struct xt_xlate *xl, xt_xlate_add(xl, "{ "); for (i = 0; i < multiinfo->count; i++) { - xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]); + xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]); if (multiinfo->pflags[i]) xt_xlate_add(xl, "-%u", multiinfo->ports[++i]); } diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate index bf015265..4f0c9c02 100644 --- a/extensions/libxt_multiport.txlate +++ b/extensions/libxt_multiport.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81 } counter accept +nft add rule ip filter INPUT ip protocol tcp tcp dport { 80, 81 } counter accept iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c index d27d84ca..580861d3 100644 --- a/extensions/libxt_time.c +++ b/extensions/libxt_time.c @@ -466,9 +466,10 @@ static int time_xlate(struct xt_xlate *xl, const struct xt_time_info *info = (const struct xt_time_info *)params->match->data; unsigned int h, m, s, - i, sep, mask, count; + i, mask, count; time_t tt_start, tt_stop; struct tm *t_start, *t_stop; + const char *sep = ""; if (info->date_start != 0 || info->date_stop != INT_MAX) { @@ -498,7 +499,6 @@ static int time_xlate(struct xt_xlate *xl, if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) return 0; if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) { - sep = 0; mask = info->weekdays_match; count = time_count_weekdays(mask); @@ -507,12 +507,8 @@ static int time_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "{"); for (i = 1; i <= 7; ++i) if (mask & (1 << i)) { - if (sep) - xt_xlate_add(xl, ",%u", i%7); - else { - xt_xlate_add(xl, "%u", i%7); - ++sep; - } + xt_xlate_add(xl, "%s%u", sep, i%7); + sep = ", "; } if (count > 1) xt_xlate_add(xl, "}"); diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate index 6aea2aed..5577c6ca 100644 --- a/extensions/libxt_time.txlate +++ b/extensions/libxt_time.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta day { 6,0 } counter reject +nft add rule ip filter INPUT icmp type echo-request meta day { 6, 0 } counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject @@ -20,7 +20,7 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1,2,3,4,5 } counter reject +nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1, 2, 3, 4, 5 } counter reject iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6,0 } counter reject +nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6, 0 } counter reject -- cgit v1.2.3 From 71e159f62451736f217792a7f8cfa8ab00add4d0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 29 Nov 2022 15:21:01 +0100 Subject: tests: shell: Test selective ebtables flushing Found this on disk, maybe there was a problem with this and among match at some point? Anyway, it is relevant again since it fails recently. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/ebtables/0006-flush_0 | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 iptables/tests/shell/testcases/ebtables/0006-flush_0 diff --git a/iptables/tests/shell/testcases/ebtables/0006-flush_0 b/iptables/tests/shell/testcases/ebtables/0006-flush_0 new file mode 100755 index 00000000..5d714529 --- /dev/null +++ b/iptables/tests/shell/testcases/ebtables/0006-flush_0 @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + +# there is no legacy backend to test +[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:90:90=192.168.0.1 -j DROP' + +$XT_MULTI ebtables-restore <<<$RULESET +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT' + +$XT_MULTI ebtables -t nat -F +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT' + +$XT_MULTI ebtables -t filter -F +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') -- cgit v1.2.3 From 83604e7f7327b6b3197f98b4e579a2b88a4c7356 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 30 Nov 2022 10:31:52 +0100 Subject: xlate: get rid of escape_quotes Its not necessary to escape " characters, we can let xtables-translate print the entire translation/command enclosed in '' chracters, i.e. nft 'add rule ...', this also takes care of [, { and other special characters that some shells might parse otherwise (when copy-pasting translated output). The escape_quotes struct member is retained to avoid an ABI breakage. This breaks all xlate test cases, fixup in followup patches. v3: no need to escape ', replace strcmp(x, "") with x[0] (Phil Sutter) Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- extensions/libebt_log.c | 8 ++------ extensions/libebt_nflog.c | 8 ++------ extensions/libxt_LOG.c | 8 ++------ extensions/libxt_NFLOG.c | 12 ++++-------- extensions/libxt_comment.c | 7 +------ extensions/libxt_helper.c | 8 ++------ include/xtables.h | 4 ++-- iptables/nft-bridge.c | 2 -- iptables/xtables-eb-translate.c | 12 ++++++------ iptables/xtables-translate.c | 22 ++++++++++------------ 10 files changed, 31 insertions(+), 60 deletions(-) diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 13c7fafe..04506219 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -181,12 +181,8 @@ static int brlog_xlate(struct xt_xlate *xl, const struct ebt_log_info *loginfo = (const void *)params->target->data; xt_xlate_add(xl, "log"); - if (loginfo->prefix[0]) { - if (params->escape_quotes) - xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); - else - xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); - } + if (loginfo->prefix[0]) + xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); if (loginfo->loglevel != LOG_DEFAULT_LEVEL) xt_xlate_add(xl, " level %s", eight_priority[loginfo->loglevel].c_name); diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c index 9801f358..115e15da 100644 --- a/extensions/libebt_nflog.c +++ b/extensions/libebt_nflog.c @@ -130,12 +130,8 @@ static int brnflog_xlate(struct xt_xlate *xl, const struct ebt_nflog_info *info = (void *)params->target->data; xt_xlate_add(xl, "log "); - if (info->prefix[0] != '\0') { - if (params->escape_quotes) - xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix); - else - xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); - } + if (info->prefix[0] != '\0') + xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); xt_xlate_add(xl, "group %u ", info->group); diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c index e3f4290b..b6fe0b2e 100644 --- a/extensions/libxt_LOG.c +++ b/extensions/libxt_LOG.c @@ -151,12 +151,8 @@ static int LOG_xlate(struct xt_xlate *xl, const char *pname = priority2name(loginfo->level); xt_xlate_add(xl, "log"); - if (strcmp(loginfo->prefix, "") != 0) { - if (params->escape_quotes) - xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); - else - xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); - } + if (strcmp(loginfo->prefix, "") != 0) + xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); if (loginfo->level != LOG_DEFAULT_LEVEL && pname) xt_xlate_add(xl, " level %s", pname); diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 7a12e5ac..d12ef044 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -112,16 +112,12 @@ static void NFLOG_save(const void *ip, const struct xt_entry_target *target) } static void nflog_print_xlate(const struct xt_nflog_info *info, - struct xt_xlate *xl, bool escape_quotes) + struct xt_xlate *xl) { xt_xlate_add(xl, "log "); - if (info->prefix[0] != '\0') { - if (escape_quotes) - xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix); - else - xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); + if (info->prefix[0] != '\0') + xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); - } if (info->flags & XT_NFLOG_F_COPY_LEN) xt_xlate_add(xl, "snaplen %u ", info->len); if (info->threshold != XT_NFLOG_DEFAULT_THRESHOLD) @@ -135,7 +131,7 @@ static int NFLOG_xlate(struct xt_xlate *xl, const struct xt_nflog_info *info = (struct xt_nflog_info *)params->target->data; - nflog_print_xlate(info, xl, params->escape_quotes); + nflog_print_xlate(info, xl); return 1; } diff --git a/extensions/libxt_comment.c b/extensions/libxt_comment.c index 69795b6c..e9c539f6 100644 --- a/extensions/libxt_comment.c +++ b/extensions/libxt_comment.c @@ -55,12 +55,7 @@ static int comment_xlate(struct xt_xlate *xl, char comment[XT_MAX_COMMENT_LEN + sizeof("\\\"\\\"")]; commentinfo->comment[XT_MAX_COMMENT_LEN - 1] = '\0'; - if (params->escape_quotes) - snprintf(comment, sizeof(comment), "\\\"%s\\\"", - commentinfo->comment); - else - snprintf(comment, sizeof(comment), "\"%s\"", - commentinfo->comment); + snprintf(comment, sizeof(comment), "\"%s\"", commentinfo->comment); xt_xlate_add_comment(xl, comment); diff --git a/extensions/libxt_helper.c b/extensions/libxt_helper.c index 2afbf996..0f72eec6 100644 --- a/extensions/libxt_helper.c +++ b/extensions/libxt_helper.c @@ -50,12 +50,8 @@ static int helper_xlate(struct xt_xlate *xl, { const struct xt_helper_info *info = (const void *)params->match->data; - if (params->escape_quotes) - xt_xlate_add(xl, "ct helper%s \\\"%s\\\"", - info->invert ? " !=" : "", info->name); - else - xt_xlate_add(xl, "ct helper%s \"%s\"", - info->invert ? " !=" : "", info->name); + xt_xlate_add(xl, "ct helper%s \"%s\"", + info->invert ? " !=" : "", info->name); return 1; } diff --git a/include/xtables.h b/include/xtables.h index dad1949e..4ffc8ec5 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -211,14 +211,14 @@ struct xt_xlate_mt_params { const void *ip; const struct xt_entry_match *match; int numeric; - bool escape_quotes; + bool escape_quotes; /* not used anymore, retained for ABI */ }; struct xt_xlate_tg_params { const void *ip; const struct xt_entry_target *target; int numeric; - bool escape_quotes; + bool escape_quotes; /* not used anymore, retained for ABI */ }; /* Include file for additions: new matches and targets. */ diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 31800913..15dfc585 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -786,7 +786,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_mt_params mt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .match = matchp->m, }; @@ -799,7 +798,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_tg_params wt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .target = watcherp->t, }; diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index f09883cd..13b6b864 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -156,17 +156,17 @@ static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse const struct iptables_command_state *cs, bool append) { struct xt_xlate *xl = xt_xlate_alloc(10240); + const char *tick = cs->restore ? "" : "'"; int ret; - if (append) { - xt_xlate_add(xl, "add rule bridge %s %s ", p->table, p->chain); - } else { - xt_xlate_add(xl, "insert rule bridge %s %s ", p->table, p->chain); - } + xt_xlate_add(xl, "%s%s rule bridge %s %s ", tick, + append ? "add" : "insert", p->table, p->chain); ret = h->ops->xlate(cs, xl); if (ret) - printf("%s\n", xt_xlate_get(xl)); + printf("%s%s\n", xt_xlate_get(xl), tick); + else + printf("%s ", tick); xt_xlate_free(xl); return ret; diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 4e8db4be..6b71fcef 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -87,7 +87,6 @@ int xlate_action(const struct iptables_command_state *cs, bool goto_set, .ip = (const void *)&cs->fw, .target = cs->target->t, .numeric = numeric, - .escape_quotes = !cs->restore, }; ret = cs->target->xlate(xl, ¶ms); } @@ -114,7 +113,6 @@ int xlate_matches(const struct iptables_command_state *cs, struct xt_xlate *xl) .ip = (const void *)&cs->fw, .match = matchp->match->m, .numeric = numeric, - .escape_quotes = !cs->restore, }; if (!matchp->match->xlate) @@ -150,6 +148,7 @@ static int nft_rule_xlate_add(struct nft_handle *h, bool append) { struct xt_xlate *xl = xt_xlate_alloc(10240); + const char *tick = cs->restore ? "" : "'"; const char *set; int ret; @@ -160,21 +159,20 @@ static int nft_rule_xlate_add(struct nft_handle *h, set = xt_xlate_set_get(xl); if (set[0]) { - printf("add set %s %s %s\n", family2str[h->family], p->table, - xt_xlate_set_get(xl)); + printf("%sadd set %s %s %s%s\n", + tick, family2str[h->family], p->table, + xt_xlate_set_get(xl), tick); if (!cs->restore && p->command != CMD_NONE) printf("nft "); } - if (append) { - printf("add rule %s %s %s ", - family2str[h->family], p->table, p->chain); - } else { - printf("insert rule %s %s %s ", - family2str[h->family], p->table, p->chain); - } - printf("%s\n", xt_xlate_rule_get(xl)); + printf("%s%s rule %s %s %s ", + tick, + append ? "add" : "insert", + family2str[h->family], p->table, p->chain); + + printf("%s%s\n", xt_xlate_rule_get(xl), tick); err_out: xt_xlate_free(xl); -- cgit v1.2.3 From 09d63e818ae0d9a09b3f665b14668beef85c47e9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 30 Nov 2022 10:31:53 +0100 Subject: extensions: change expected output for new format Now that xtables-translate encloses the entire command line in ', update the test cases accordingly. Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- extensions/generic.txlate | 56 ++++++++++++++++++------------------ extensions/libebt_dnat.txlate | 6 ++-- extensions/libebt_ip.txlate | 18 ++++++------ extensions/libebt_ip6.txlate | 20 ++++++------- extensions/libebt_limit.txlate | 6 ++-- extensions/libebt_log.txlate | 10 +++---- extensions/libebt_mark.txlate | 8 +++--- extensions/libebt_mark_m.txlate | 10 +++---- extensions/libebt_nflog.txlate | 8 +++--- extensions/libebt_pkttype.txlate | 14 ++++----- extensions/libebt_snat.txlate | 4 +-- extensions/libebt_vlan.txlate | 8 +++--- extensions/libip6t_LOG.txlate | 6 ++-- extensions/libip6t_MASQUERADE.txlate | 12 ++++---- extensions/libip6t_REJECT.txlate | 6 ++-- extensions/libip6t_SNAT.txlate | 8 +++--- extensions/libip6t_ah.txlate | 12 ++++---- extensions/libip6t_frag.txlate | 12 ++++---- extensions/libip6t_hbh.txlate | 4 +-- extensions/libip6t_hl.txlate | 4 +-- extensions/libip6t_icmp6.txlate | 6 ++-- extensions/libip6t_mh.txlate | 4 +-- extensions/libip6t_rt.txlate | 10 +++---- extensions/libipt_LOG.txlate | 4 +-- extensions/libipt_MASQUERADE.txlate | 12 ++++---- extensions/libipt_REJECT.txlate | 6 ++-- extensions/libipt_SNAT.txlate | 10 +++---- extensions/libipt_ah.txlate | 6 ++-- extensions/libipt_icmp.txlate | 8 +++--- extensions/libipt_realm.txlate | 8 +++--- extensions/libipt_ttl.txlate | 4 +-- extensions/libxt_AUDIT.txlate | 6 ++-- extensions/libxt_CLASSIFY.txlate | 6 ++-- extensions/libxt_CONNMARK.txlate | 16 +++++------ extensions/libxt_DNAT.txlate | 24 ++++++++-------- extensions/libxt_DSCP.txlate | 4 +-- extensions/libxt_MARK.txlate | 18 ++++++------ extensions/libxt_NFLOG.txlate | 10 +++---- extensions/libxt_NFQUEUE.txlate | 6 ++-- extensions/libxt_NOTRACK.txlate | 2 +- extensions/libxt_REDIRECT.txlate | 20 ++++++------- extensions/libxt_SYNPROXY.txlate | 2 +- extensions/libxt_TCPMSS.txlate | 4 +-- extensions/libxt_TEE.txlate | 8 +++--- extensions/libxt_TOS.txlate | 18 ++++++------ extensions/libxt_TRACE.txlate | 2 +- extensions/libxt_addrtype.txlate | 8 +++--- extensions/libxt_cgroup.txlate | 4 +-- extensions/libxt_cluster.txlate | 18 ++++++------ extensions/libxt_comment.txlate | 6 ++-- extensions/libxt_connbytes.txlate | 10 +++---- extensions/libxt_connlabel.txlate | 4 +-- extensions/libxt_connlimit.txlate | 16 +++++------ extensions/libxt_connmark.txlate | 10 +++---- extensions/libxt_conntrack.txlate | 40 +++++++++++++------------- extensions/libxt_cpu.txlate | 4 +-- extensions/libxt_dccp.txlate | 14 ++++----- extensions/libxt_devgroup.txlate | 12 ++++---- extensions/libxt_dscp.txlate | 4 +-- extensions/libxt_ecn.txlate | 20 ++++++------- extensions/libxt_esp.txlate | 8 +++--- extensions/libxt_hashlimit.txlate | 4 +-- extensions/libxt_helper.txlate | 4 +-- extensions/libxt_ipcomp.txlate | 4 +-- extensions/libxt_iprange.txlate | 10 +++---- extensions/libxt_length.txlate | 8 +++--- extensions/libxt_limit.txlate | 6 ++-- extensions/libxt_mac.txlate | 4 +-- extensions/libxt_mark.txlate | 4 +-- extensions/libxt_multiport.txlate | 10 +++---- extensions/libxt_owner.txlate | 6 ++-- extensions/libxt_pkttype.txlate | 6 ++-- extensions/libxt_policy.txlate | 4 +-- extensions/libxt_quota.txlate | 4 +-- extensions/libxt_rpfilter.txlate | 6 ++-- extensions/libxt_sctp.txlate | 30 +++++++++---------- extensions/libxt_statistic.txlate | 4 +-- extensions/libxt_tcp.txlate | 22 +++++++------- extensions/libxt_tcpmss.txlate | 8 +++--- extensions/libxt_time.txlate | 18 ++++++------ extensions/libxt_udp.txlate | 8 +++--- 81 files changed, 402 insertions(+), 402 deletions(-) diff --git a/extensions/generic.txlate b/extensions/generic.txlate index 6779d6f8..7e879fd5 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -1,90 +1,90 @@ iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept' iptables-translate -F -t nat nft flush table ip nat iptables-translate -I INPUT -i iifname -s 10.0.0.0/8 -nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter +nft 'insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter' iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8 -nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter +nft 'add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter' iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0 -nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter +nft 'insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter' iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0 -nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter +nft 'insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter' iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255 -nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter +nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter' iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255 -nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter +nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter' iptables-translate -I INPUT -s 0.0.0.0/16 -nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter +nft 'insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter' iptables-translate -I INPUT -s 0.0.0.0/0 -nft insert rule ip filter INPUT counter +nft 'insert rule ip filter INPUT counter' iptables-translate -I INPUT ! -s 0.0.0.0/0 -nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter +nft 'insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter' ip6tables-translate -I INPUT -i iifname -s feed::/16 -nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter +nft 'insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter' ip6tables-translate -A INPUT -i iif+ ! -d feed::/16 -nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter +nft 'add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter' ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00:: -nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter +nft 'insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter' ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0 -nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter +nft 'insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter' ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff -nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter +nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter' ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff -nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter +nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter' ip6tables-translate -I INPUT -s ::/16 -nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter +nft 'insert rule ip6 filter INPUT ip6 saddr ::/16 counter' ip6tables-translate -I INPUT -s ::/0 -nft insert rule ip6 filter INPUT counter +nft 'insert rule ip6 filter INPUT counter' ip6tables-translate -I INPUT ! -s ::/0 -nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter +nft 'insert rule ip6 filter INPUT ip6 saddr != ::/0 counter' ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0 -nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter +nft 'insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter' ebtables-translate -A FORWARD ! -i iname --logical-in ilogname -o out+ --logical-out lout+ -d 1:2:3:4:de:af -nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter +nft 'add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter' ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00 -nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter +nft 'insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter' ebtables-translate -I INPUT -p Length -nft insert rule bridge filter INPUT ether type < 0x0600 counter +nft 'insert rule bridge filter INPUT ether type < 0x0600 counter' ebtables-translate -I INPUT -p ! Length -nft insert rule bridge filter INPUT ether type >= 0x0600 counter +nft 'insert rule bridge filter INPUT ether type >= 0x0600 counter' # asterisk is not special in iptables and it is even a valid interface name iptables-translate -A FORWARD -i '*' -o 'eth*foo' -nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter +nft 'add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter' # escape all asterisks but translate only the first plus character iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++' -nft add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter +nft 'add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter' # skip for always matching interface names iptables-translate -A FORWARD -i '+' -nft add rule ip filter FORWARD counter +nft 'add rule ip filter FORWARD counter' # match against invalid interface name to simulate never matching rule iptables-translate -A FORWARD ! -i '+' -nft add rule ip filter FORWARD iifname "INVAL/D" counter +nft 'add rule ip filter FORWARD iifname "INVAL/D" counter' diff --git a/extensions/libebt_dnat.txlate b/extensions/libebt_dnat.txlate index 2652dd55..9f305c76 100644 --- a/extensions/libebt_dnat.txlate +++ b/extensions/libebt_dnat.txlate @@ -1,8 +1,8 @@ ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter +nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter' ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter +nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter' ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff continue counter +nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff continue counter' diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index b5882c34..75c1db24 100644 --- a/extensions/libebt_ip.txlate +++ b/extensions/libebt_ip.txlate @@ -1,26 +1,26 @@ ebtables-translate -A FORWARD -p ip --ip-src ! 192.168.0.0/24 -j ACCEPT -nft add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept +nft 'add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept' ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1 -nft insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter +nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter' ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff -nft insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter +nft 'insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter' ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22 -nft add rule bridge filter FORWARD tcp dport 22 counter +nft 'add rule bridge filter FORWARD tcp dport 22 counter' ebtables-translate -A FORWARD -p ip --ip-proto udp --ip-sport 1024:65535 -nft add rule bridge filter FORWARD udp sport 1024-65535 counter +nft 'add rule bridge filter FORWARD udp sport 1024-65535 counter' ebtables-translate -A FORWARD -p ip --ip-proto 253 -nft add rule bridge filter FORWARD ip protocol 253 counter +nft 'add rule bridge filter FORWARD ip protocol 253 counter' ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type "echo-request" -nft add rule bridge filter FORWARD icmp type 8 counter +nft 'add rule bridge filter FORWARD icmp type 8 counter' ebtables-translate -A FORWARD -p ip --ip-proto icmp --ip-icmp-type 1/1 -nft add rule bridge filter FORWARD icmp type 1 icmp code 1 counter +nft 'add rule bridge filter FORWARD icmp type 1 icmp code 1 counter' ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type ! 1:10 -nft add rule bridge filter FORWARD icmp type != 1-10 counter +nft 'add rule bridge filter FORWARD icmp type != 1-10 counter' diff --git a/extensions/libebt_ip6.txlate b/extensions/libebt_ip6.txlate index 0271734c..0debbe12 100644 --- a/extensions/libebt_ip6.txlate +++ b/extensions/libebt_ip6.txlate @@ -1,29 +1,29 @@ ebtables-translate -A FORWARD -p ip6 --ip6-src ! dead::beef/64 -j ACCEPT -nft add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept +nft 'add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept' ebtables-translate -A FORWARD -p ip6 ! --ip6-dst dead:beef::/64 -j ACCEPT -nft add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept +nft 'add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept' ebtables-translate -I FORWARD -p ip6 --ip6-dst f00:ba:: -nft insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter +nft 'insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter' ebtables-translate -I OUTPUT -o eth0 -p ip6 --ip6-tclass 0xff -nft insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter +nft 'insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto tcp --ip6-dport 22 -nft add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter +nft 'add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto udp --ip6-sport 1024:65535 -nft add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter +nft 'add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto 253 -nft add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter +nft 'add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type "echo-request" -nft add rule bridge filter FORWARD icmpv6 type 128 counter +nft 'add rule bridge filter FORWARD icmpv6 type 128 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1 -nft add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter +nft 'add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type ! 1:10 -nft add rule bridge filter FORWARD icmpv6 type != 1-10 counter +nft 'add rule bridge filter FORWARD icmpv6 type != 1-10 counter' diff --git a/extensions/libebt_limit.txlate b/extensions/libebt_limit.txlate index b6af15d5..adcce3ed 100644 --- a/extensions/libebt_limit.txlate +++ b/extensions/libebt_limit.txlate @@ -1,8 +1,8 @@ ebtables-translate -A INPUT --limit 3/m --limit-burst 3 -nft add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter +nft 'add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter' ebtables-translate -A INPUT --limit 10/s --limit-burst 5 -nft add rule bridge filter INPUT limit rate 10/second burst 5 packets counter +nft 'add rule bridge filter INPUT limit rate 10/second burst 5 packets counter' ebtables-translate -A INPUT --limit 10/s --limit-burst 0 -nft add rule bridge filter INPUT limit rate 10/second counter +nft 'add rule bridge filter INPUT limit rate 10/second counter' diff --git a/extensions/libebt_log.txlate b/extensions/libebt_log.txlate index 7ef8d5e1..9847e4c1 100644 --- a/extensions/libebt_log.txlate +++ b/extensions/libebt_log.txlate @@ -1,15 +1,15 @@ ebtables-translate -A INPUT --log -nft add rule bridge filter INPUT log level notice flags ether counter +nft 'add rule bridge filter INPUT log level notice flags ether counter' ebtables-translate -A INPUT --log-level 1 -nft add rule bridge filter INPUT log level alert flags ether counter +nft 'add rule bridge filter INPUT log level alert flags ether counter' ebtables-translate -A INPUT --log-level crit -nft add rule bridge filter INPUT log level crit flags ether counter +nft 'add rule bridge filter INPUT log level crit flags ether counter' ebtables-translate -A INPUT --log-level emerg --log-ip --log-arp --log-ip6 -nft add rule bridge filter INPUT log level emerg flags ether counter +nft 'add rule bridge filter INPUT log level emerg flags ether counter' ebtables-translate -A INPUT --log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo -nft add rule bridge filter INPUT log prefix "foo" level crit flags ether counter +nft 'add rule bridge filter INPUT log prefix "foo" level crit flags ether counter' diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate index 7529302d..d006e8ac 100644 --- a/extensions/libebt_mark.txlate +++ b/extensions/libebt_mark.txlate @@ -1,11 +1,11 @@ ebtables-translate -A INPUT --mark-set 42 -nft add rule bridge filter INPUT meta mark set 0x2a accept counter +nft 'add rule bridge filter INPUT meta mark set 0x2a accept counter' ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN -nft add rule bridge filter INPUT meta mark set meta mark or 0x2a return counter +nft 'add rule bridge filter INPUT meta mark set meta mark or 0x2a return counter' ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT -nft add rule bridge filter INPUT meta mark set meta mark and 0x2a accept counter +nft 'add rule bridge filter INPUT meta mark set meta mark and 0x2a accept counter' ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP -nft add rule bridge filter INPUT meta mark set meta mark xor 0x2a drop counter +nft 'add rule bridge filter INPUT meta mark set meta mark xor 0x2a drop counter' diff --git a/extensions/libebt_mark_m.txlate b/extensions/libebt_mark_m.txlate index 7b44425b..2981a564 100644 --- a/extensions/libebt_mark_m.txlate +++ b/extensions/libebt_mark_m.txlate @@ -1,14 +1,14 @@ ebtables-translate -A INPUT --mark 42 -nft add rule bridge filter INPUT meta mark 0x2a counter +nft 'add rule bridge filter INPUT meta mark 0x2a counter' ebtables-translate -A INPUT ! --mark 42 -nft add rule bridge filter INPUT meta mark != 0x2a counter +nft 'add rule bridge filter INPUT meta mark != 0x2a counter' ebtables-translate -A INPUT --mark ! 42 -nft add rule bridge filter INPUT meta mark != 0x2a counter +nft 'add rule bridge filter INPUT meta mark != 0x2a counter' ebtables-translate -A INPUT --mark ! 0x1/0xff -nft add rule bridge filter INPUT meta mark and 0xff != 0x1 counter +nft 'add rule bridge filter INPUT meta mark and 0xff != 0x1 counter' ebtables-translate -A INPUT --mark /0x02 -nft add rule bridge filter INPUT meta mark and 0x2 != 0 counter +nft 'add rule bridge filter INPUT meta mark and 0x2 != 0 counter' diff --git a/extensions/libebt_nflog.txlate b/extensions/libebt_nflog.txlate index bc3f5364..6f292fd2 100644 --- a/extensions/libebt_nflog.txlate +++ b/extensions/libebt_nflog.txlate @@ -1,11 +1,11 @@ ebtables-translate -A INPUT --nflog -nft add rule bridge filter INPUT log group 1 counter +nft 'add rule bridge filter INPUT log group 1 counter' ebtables-translate -A INPUT --nflog-group 42 -nft add rule bridge filter INPUT log group 42 counter +nft 'add rule bridge filter INPUT log group 42 counter' ebtables-translate -A INPUT --nflog-range 42 -nft add rule bridge filter INPUT log group 1 snaplen 42 counter +nft 'add rule bridge filter INPUT log group 1 snaplen 42 counter' ebtables-translate -A INPUT --nflog-threshold 100 --nflog-prefix foo -nft add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter +nft 'add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter' diff --git a/extensions/libebt_pkttype.txlate b/extensions/libebt_pkttype.txlate index 94d016d9..6a828a98 100644 --- a/extensions/libebt_pkttype.txlate +++ b/extensions/libebt_pkttype.txlate @@ -1,20 +1,20 @@ ebtables-translate -A INPUT --pkttype-type host -nft add rule bridge filter INPUT meta pkttype host counter +nft 'add rule bridge filter INPUT meta pkttype host counter' ebtables-translate -A INPUT ! --pkttype-type broadcast -nft add rule bridge filter INPUT meta pkttype != broadcast counter +nft 'add rule bridge filter INPUT meta pkttype != broadcast counter' ebtables-translate -A INPUT --pkttype-type ! multicast -nft add rule bridge filter INPUT meta pkttype != multicast counter +nft 'add rule bridge filter INPUT meta pkttype != multicast counter' ebtables-translate -A INPUT --pkttype-type otherhost -nft add rule bridge filter INPUT meta pkttype other counter +nft 'add rule bridge filter INPUT meta pkttype other counter' ebtables-translate -A INPUT --pkttype-type outgoing -nft add rule bridge filter INPUT meta pkttype 4 counter +nft 'add rule bridge filter INPUT meta pkttype 4 counter' ebtables-translate -A INPUT --pkttype-type loopback -nft add rule bridge filter INPUT meta pkttype 5 counter +nft 'add rule bridge filter INPUT meta pkttype 5 counter' ebtables-translate -A INPUT --pkttype-type fastroute -nft add rule bridge filter INPUT meta pkttype 6 counter +nft 'add rule bridge filter INPUT meta pkttype 6 counter' diff --git a/extensions/libebt_snat.txlate b/extensions/libebt_snat.txlate index 0d846024..857a6052 100644 --- a/extensions/libebt_snat.txlate +++ b/extensions/libebt_snat.txlate @@ -1,5 +1,5 @@ ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ --to-source de:ad:00:be:ee:ff -nft add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter +nft 'add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter' ebtables-translate -t nat -A POSTROUTING -o someport --to-src de:ad:00:be:ee:ff --snat-target CONTINUE -nft add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter +nft 'add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter' diff --git a/extensions/libebt_vlan.txlate b/extensions/libebt_vlan.txlate index 2ab62d53..5d21e3eb 100644 --- a/extensions/libebt_vlan.txlate +++ b/extensions/libebt_vlan.txlate @@ -1,11 +1,11 @@ ebtables-translate -A INPUT -p 802_1Q --vlan-id 42 -nft add rule bridge filter INPUT vlan id 42 counter +nft 'add rule bridge filter INPUT vlan id 42 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-prio ! 1 -nft add rule bridge filter INPUT vlan pcp != 1 counter +nft 'add rule bridge filter INPUT vlan pcp != 1 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-encap ip -nft add rule bridge filter INPUT vlan type 0x0800 counter +nft 'add rule bridge filter INPUT vlan type 0x0800 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-encap ipv6 ! --vlan-id 1 -nft add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter +nft 'add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter' diff --git a/extensions/libip6t_LOG.txlate b/extensions/libip6t_LOG.txlate index 2820a82c..29ffce72 100644 --- a/extensions/libip6t_LOG.txlate +++ b/extensions/libip6t_LOG.txlate @@ -1,8 +1,8 @@ iptables-translate -I INPUT -j LOG -nft insert rule ip filter INPUT counter log +nft 'insert rule ip filter INPUT counter log' ip6tables-translate -A FORWARD -p tcp -j LOG --log-level debug -nft add rule ip6 filter FORWARD meta l4proto tcp counter log level debug +nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log level debug' ip6tables-translate -A FORWARD -p tcp -j LOG --log-prefix "Checking log" -nft add rule ip6 filter FORWARD meta l4proto tcp counter log prefix \"Checking log\" +nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log prefix "Checking log"' diff --git a/extensions/libip6t_MASQUERADE.txlate b/extensions/libip6t_MASQUERADE.txlate index a2f98080..3f003477 100644 --- a/extensions/libip6t_MASQUERADE.txlate +++ b/extensions/libip6t_MASQUERADE.txlate @@ -1,17 +1,17 @@ ip6tables-translate -t nat -A POSTROUTING -j MASQUERADE -nft add rule ip6 nat POSTROUTING counter masquerade +nft 'add rule ip6 nat POSTROUTING counter masquerade' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10 +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade fully-random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade fully-random' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random,fully-random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random,fully-random' diff --git a/extensions/libip6t_REJECT.txlate b/extensions/libip6t_REJECT.txlate index cfa35ebf..184713d1 100644 --- a/extensions/libip6t_REJECT.txlate +++ b/extensions/libip6t_REJECT.txlate @@ -1,8 +1,8 @@ ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT -nft add rule ip6 filter FORWARD tcp dport 22 counter reject +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject' ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp6-reject-route -nft add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route' ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset -nft add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset' diff --git a/extensions/libip6t_SNAT.txlate b/extensions/libip6t_SNAT.txlate index 44f2fcea..e5f6f735 100644 --- a/extensions/libip6t_SNAT.txlate +++ b/extensions/libip6t_SNAT.txlate @@ -1,11 +1,11 @@ ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80 -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80 +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20 -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20 +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent' diff --git a/extensions/libip6t_ah.txlate b/extensions/libip6t_ah.txlate index c6b09a2e..cc33ac27 100644 --- a/extensions/libip6t_ah.txlate +++ b/extensions/libip6t_ah.txlate @@ -1,17 +1,17 @@ ip6tables-translate -A INPUT -m ah --ahspi 500 -j DROP -nft add rule ip6 filter INPUT ah spi 500 counter drop +nft 'add rule ip6 filter INPUT ah spi 500 counter drop' ip6tables-translate -A INPUT -m ah --ahspi 500:550 -j DROP -nft add rule ip6 filter INPUT ah spi 500-550 counter drop +nft 'add rule ip6 filter INPUT ah spi 500-550 counter drop' ip6tables-translate -A INPUT -m ah ! --ahlen 120 -nft add rule ip6 filter INPUT ah hdrlength != 120 counter +nft 'add rule ip6 filter INPUT ah hdrlength != 120 counter' ip6tables-translate -A INPUT -m ah --ahres -nft add rule ip6 filter INPUT ah reserved 1 counter +nft 'add rule ip6 filter INPUT ah reserved 1 counter' ip6tables-translate -A INPUT -m ah --ahspi 500 ! --ahlen 120 -j DROP -nft add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop +nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop' ip6tables-translate -A INPUT -m ah --ahspi 500 --ahlen 120 --ahres -j ACCEPT -nft add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept +nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept' diff --git a/extensions/libip6t_frag.txlate b/extensions/libip6t_frag.txlate index e8bd9d4b..33fc0631 100644 --- a/extensions/libip6t_frag.txlate +++ b/extensions/libip6t_frag.txlate @@ -1,17 +1,17 @@ ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100 --fragres --fragmore -j ACCEPT -nft add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept +nft 'add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept' ip6tables-translate -t filter -A INPUT -m frag ! --fragid 100:200 -j ACCEPT -nft add rule ip6 filter INPUT frag id != 100-200 counter accept +nft 'add rule ip6 filter INPUT frag id != 100-200 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fraglast -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fragfirst -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fraglast -j ACCEPT -nft add rule ip6 filter INPUT frag more-fragments 0 counter accept +nft 'add rule ip6 filter INPUT frag more-fragments 0 counter accept' diff --git a/extensions/libip6t_hbh.txlate b/extensions/libip6t_hbh.txlate index 28101fd7..a753df0d 100644 --- a/extensions/libip6t_hbh.txlate +++ b/extensions/libip6t_hbh.txlate @@ -1,5 +1,5 @@ ip6tables-translate -t filter -A INPUT -m hbh --hbh-len 22 -nft add rule ip6 filter INPUT hbh hdrlength 22 counter +nft 'add rule ip6 filter INPUT hbh hdrlength 22 counter' ip6tables-translate -t filter -A INPUT -m hbh ! --hbh-len 22 -nft add rule ip6 filter INPUT hbh hdrlength != 22 counter +nft 'add rule ip6 filter INPUT hbh hdrlength != 22 counter' diff --git a/extensions/libip6t_hl.txlate b/extensions/libip6t_hl.txlate index 17563938..9ff0df9c 100644 --- a/extensions/libip6t_hl.txlate +++ b/extensions/libip6t_hl.txlate @@ -1,5 +1,5 @@ ip6tables-translate -t nat -A postrouting -m hl --hl-gt 3 -nft add rule ip6 nat postrouting ip6 hoplimit gt 3 counter +nft 'add rule ip6 nat postrouting ip6 hoplimit gt 3 counter' ip6tables-translate -t nat -A postrouting -m hl ! --hl-eq 3 -nft add rule ip6 nat postrouting ip6 hoplimit != 3 counter +nft 'add rule ip6 nat postrouting ip6 hoplimit != 3 counter' diff --git a/extensions/libip6t_icmp6.txlate b/extensions/libip6t_icmp6.txlate index 15481ad6..324a48b9 100644 --- a/extensions/libip6t_icmp6.txlate +++ b/extensions/libip6t_icmp6.txlate @@ -1,8 +1,8 @@ ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type 1 -j LOG -nft add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log +nft 'add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log' ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type neighbour-advertisement -j LOG -nft add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log +nft 'add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log' ip6tables-translate -t filter -A INPUT -m icmp6 ! --icmpv6-type packet-too-big -j LOG -nft add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log +nft 'add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log' diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate index f5d638c0..4dfaf46a 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 mobility-header 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 mobility-header 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/libip6t_rt.txlate b/extensions/libip6t_rt.txlate index 6464cf9e..3578bcba 100644 --- a/extensions/libip6t_rt.txlate +++ b/extensions/libip6t_rt.txlate @@ -1,14 +1,14 @@ ip6tables-translate -A INPUT -m rt --rt-type 0 -j DROP -nft add rule ip6 filter INPUT rt type 0 counter drop +nft 'add rule ip6 filter INPUT rt type 0 counter drop' ip6tables-translate -A INPUT -m rt ! --rt-len 22 -j DROP -nft add rule ip6 filter INPUT rt hdrlength != 22 counter drop +nft 'add rule ip6 filter INPUT rt hdrlength != 22 counter drop' ip6tables-translate -A INPUT -m rt --rt-segsleft 26 -j ACCEPT -nft add rule ip6 filter INPUT rt seg-left 26 counter accept +nft 'add rule ip6 filter INPUT rt seg-left 26 counter accept' ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 -j DROP -nft add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop +nft 'add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop' ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 ! --rt-segsleft 26 -j ACCEPT -nft add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept +nft 'add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept' diff --git a/extensions/libipt_LOG.txlate b/extensions/libipt_LOG.txlate index 81f64fb2..13a2ef55 100644 --- a/extensions/libipt_LOG.txlate +++ b/extensions/libipt_LOG.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -p tcp -j LOG --log-level error -nft add rule ip filter FORWARD ip protocol tcp counter log level err +nft 'add rule ip filter FORWARD ip protocol tcp counter log level err' iptables-translate -A FORWARD -p tcp -j LOG --log-prefix "Random prefix" -nft add rule ip filter FORWARD ip protocol tcp counter log prefix \"Random prefix\" +nft 'add rule ip filter FORWARD ip protocol tcp counter log prefix "Random prefix"' diff --git a/extensions/libipt_MASQUERADE.txlate b/extensions/libipt_MASQUERADE.txlate index 49f79d33..0293b05b 100644 --- a/extensions/libipt_MASQUERADE.txlate +++ b/extensions/libipt_MASQUERADE.txlate @@ -1,17 +1,17 @@ iptables-translate -t nat -A POSTROUTING -j MASQUERADE -nft add rule ip nat POSTROUTING counter masquerade +nft 'add rule ip nat POSTROUTING counter masquerade' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10 +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade fully-random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade fully-random' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade random,fully-random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random,fully-random' diff --git a/extensions/libipt_REJECT.txlate b/extensions/libipt_REJECT.txlate index a1bfb5f4..022166a6 100644 --- a/extensions/libipt_REJECT.txlate +++ b/extensions/libipt_REJECT.txlate @@ -1,8 +1,8 @@ iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT -nft add rule ip filter FORWARD tcp dport 22 counter reject +nft 'add rule ip filter FORWARD tcp dport 22 counter reject' iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp-net-unreachable -nft add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable +nft 'add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable' iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset -nft add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset +nft 'add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset' diff --git a/extensions/libipt_SNAT.txlate b/extensions/libipt_SNAT.txlate index 01592fad..83afef95 100644 --- a/extensions/libipt_SNAT.txlate +++ b/extensions/libipt_SNAT.txlate @@ -1,14 +1,14 @@ iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6 -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6 +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6' iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023 -nft add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023 +nft 'add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent' diff --git a/extensions/libipt_ah.txlate b/extensions/libipt_ah.txlate index ea3ef3e9..897c82b5 100644 --- a/extensions/libipt_ah.txlate +++ b/extensions/libipt_ah.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -p 51 -m ah --ahspi 500 -j DROP -nft add rule ip filter INPUT ah spi 500 counter drop +nft 'add rule ip filter INPUT ah spi 500 counter drop' iptables-translate -A INPUT -p 51 -m ah --ahspi 500:600 -j DROP -nft add rule ip filter INPUT ah spi 500-600 counter drop +nft 'add rule ip filter INPUT ah spi 500-600 counter drop' iptables-translate -A INPUT -p 51 -m ah ! --ahspi 50 -j DROP -nft add rule ip filter INPUT ah spi != 50 counter drop +nft 'add rule ip filter INPUT ah spi != 50 counter drop' diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate index a2aec8e2..e7208d8b 100644 --- a/extensions/libipt_icmp.txlate +++ b/extensions/libipt_icmp.txlate @@ -1,11 +1,11 @@ iptables-translate -t filter -A INPUT -m icmp --icmp-type echo-reply -j ACCEPT -nft add rule ip filter INPUT icmp type echo-reply counter accept +nft 'add rule ip filter INPUT icmp type echo-reply counter accept' iptables-translate -t filter -A INPUT -m icmp --icmp-type 3 -j ACCEPT -nft add rule ip filter INPUT icmp type destination-unreachable counter accept +nft 'add rule ip filter INPUT icmp type destination-unreachable counter accept' iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT -nft add rule ip filter INPUT icmp type != destination-unreachable counter accept +nft 'add rule ip filter INPUT icmp type != destination-unreachable counter accept' iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT -nft add rule ip filter INPUT ip protocol icmp counter accept +nft 'add rule ip filter INPUT ip protocol icmp counter accept' diff --git a/extensions/libipt_realm.txlate b/extensions/libipt_realm.txlate index 7d710294..6d134546 100644 --- a/extensions/libipt_realm.txlate +++ b/extensions/libipt_realm.txlate @@ -1,11 +1,11 @@ iptables-translate -A PREROUTING -m realm --realm 4 -nft add rule ip filter PREROUTING rtclassid 0x4 counter +nft 'add rule ip filter PREROUTING rtclassid 0x4 counter' iptables-translate -A PREROUTING -m realm --realm 5/5 -nft add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter +nft 'add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter' iptables-translate -A PREROUTING -m realm ! --realm 50 -nft add rule ip filter PREROUTING rtclassid != 0x32 counter +nft 'add rule ip filter PREROUTING rtclassid != 0x32 counter' iptables-translate -A INPUT -m realm --realm 1/0xf -nft add rule ip filter INPUT rtclassid and 0xf == 0x1 counter +nft 'add rule ip filter INPUT rtclassid and 0xf == 0x1 counter' diff --git a/extensions/libipt_ttl.txlate b/extensions/libipt_ttl.txlate index 3d5d6a70..6b90ff99 100644 --- a/extensions/libipt_ttl.txlate +++ b/extensions/libipt_ttl.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m ttl --ttl-eq 3 -j ACCEPT -nft add rule ip filter INPUT ip ttl 3 counter accept +nft 'add rule ip filter INPUT ip ttl 3 counter accept' iptables-translate -A INPUT -m ttl --ttl-gt 5 -j ACCEPT -nft add rule ip filter INPUT ip ttl gt 5 counter accept +nft 'add rule ip filter INPUT ip ttl gt 5 counter accept' diff --git a/extensions/libxt_AUDIT.txlate b/extensions/libxt_AUDIT.txlate index abd11eae..c1650b9a 100644 --- a/extensions/libxt_AUDIT.txlate +++ b/extensions/libxt_AUDIT.txlate @@ -1,8 +1,8 @@ iptables-translate -t filter -A INPUT -j AUDIT --type accept -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' iptables-translate -t filter -A INPUT -j AUDIT --type drop -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' iptables-translate -t filter -A INPUT -j AUDIT --type reject -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' diff --git a/extensions/libxt_CLASSIFY.txlate b/extensions/libxt_CLASSIFY.txlate index 3b349237..3150c69e 100644 --- a/extensions/libxt_CLASSIFY.txlate +++ b/extensions/libxt_CLASSIFY.txlate @@ -1,8 +1,8 @@ iptables-translate -A OUTPUT -j CLASSIFY --set-class 0:0 -nft add rule ip filter OUTPUT counter meta priority set none +nft 'add rule ip filter OUTPUT counter meta priority set none' iptables-translate -A OUTPUT -j CLASSIFY --set-class ffff:ffff -nft add rule ip filter OUTPUT counter meta priority set root +nft 'add rule ip filter OUTPUT counter meta priority set root' iptables-translate -A OUTPUT -j CLASSIFY --set-class 1:234 -nft add rule ip filter OUTPUT counter meta priority set 1:234 +nft 'add rule ip filter OUTPUT counter meta priority set 1:234' diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate index 99627c2b..5da4d6c7 100644 --- a/extensions/libxt_CONNMARK.txlate +++ b/extensions/libxt_CONNMARK.txlate @@ -1,23 +1,23 @@ iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0 -nft add rule ip mangle PREROUTING counter ct mark set 0x0 +nft 'add rule ip mangle PREROUTING counter ct mark set 0x0' iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-xmark 0x16/0x12 -nft add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed' iptables-translate -t mangle -A PREROUTING -j CONNMARK --and-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --or-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --save-mark -nft add rule ip mangle PREROUTING counter ct mark set mark +nft 'add rule ip mangle PREROUTING counter ct mark set mark' iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark -nft add rule ip mangle PREROUTING counter meta mark set ct mark +nft 'add rule ip mangle PREROUTING counter meta mark set ct mark' iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x23/0x42 --right-shift-mark 5 -nft add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5 +nft 'add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5' diff --git a/extensions/libxt_DNAT.txlate b/extensions/libxt_DNAT.txlate index a6597656..e005245d 100644 --- a/extensions/libxt_DNAT.txlate +++ b/extensions/libxt_DNAT.txlate @@ -1,35 +1,35 @@ iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4' iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 -nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 +nft 'add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10' iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023 +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023' iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random' iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent' ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234 -nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234 +nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234' ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234-fec0::2000 -nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000 +nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000' ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 -nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80 +nft 'add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80' ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20' ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234-fec0::2000]:1-20 -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20 +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20' ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent' ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent' diff --git a/extensions/libxt_DSCP.txlate b/extensions/libxt_DSCP.txlate index 442742ef..f7801a83 100644 --- a/extensions/libxt_DSCP.txlate +++ b/extensions/libxt_DSCP.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -j DSCP --set-dscp 1 -nft add rule ip filter OUTPUT counter ip dscp set 0x01 +nft 'add rule ip filter OUTPUT counter ip dscp set 0x01' ip6tables-translate -A OUTPUT -j DSCP --set-dscp 6 -nft add rule ip6 filter OUTPUT counter ip6 dscp set 0x06 +nft 'add rule ip6 filter OUTPUT counter ip6 dscp set 0x06' diff --git a/extensions/libxt_MARK.txlate b/extensions/libxt_MARK.txlate index d3250ab6..36ee7a3b 100644 --- a/extensions/libxt_MARK.txlate +++ b/extensions/libxt_MARK.txlate @@ -1,26 +1,26 @@ iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 0 -nft add rule ip mangle OUTPUT counter meta mark set 0x0 +nft 'add rule ip mangle OUTPUT counter meta mark set 0x0' iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --set-xmark 0x40/0x32 -nft add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --or-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark or 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark or 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --and-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark and 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --xor-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark xor 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark xor 0x40' iptables-translate -t mangle -A PREROUTING -j MARK --set-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set 0x64' iptables-translate -t mangle -A PREROUTING -j MARK --and-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set mark and 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set mark and 0x64' iptables-translate -t mangle -A PREROUTING -j MARK --or-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set mark or 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set mark or 0x64' diff --git a/extensions/libxt_NFLOG.txlate b/extensions/libxt_NFLOG.txlate index a0872c9e..ebd81be3 100644 --- a/extensions/libxt_NFLOG.txlate +++ b/extensions/libxt_NFLOG.txlate @@ -1,14 +1,14 @@ iptables-translate -A FORWARD -j NFLOG --nflog-group 32 --nflog-prefix "Prefix 1.0" -nft add rule ip filter FORWARD counter log prefix \"Prefix 1.0\" group 32 +nft 'add rule ip filter FORWARD counter log prefix "Prefix 1.0" group 32' iptables-translate -A OUTPUT -j NFLOG --nflog-group 30 -nft add rule ip filter OUTPUT counter log group 30 +nft 'add rule ip filter OUTPUT counter log group 30' iptables-translate -I INPUT -j NFLOG --nflog-threshold 2 -nft insert rule ip filter INPUT counter log queue-threshold 2 group 0 +nft 'insert rule ip filter INPUT counter log queue-threshold 2 group 0' iptables-translate -I INPUT -j NFLOG --nflog-size 256 -nft insert rule ip filter INPUT counter log snaplen 256 group 0 +nft 'insert rule ip filter INPUT counter log snaplen 256 group 0' iptables-translate -I INPUT -j NFLOG --nflog-threshold 25 -nft insert rule ip filter INPUT counter log queue-threshold 25 group 0 +nft 'insert rule ip filter INPUT counter log queue-threshold 25 group 0' diff --git a/extensions/libxt_NFQUEUE.txlate b/extensions/libxt_NFQUEUE.txlate index 3d188a7a..3698dcbc 100644 --- a/extensions/libxt_NFQUEUE.txlate +++ b/extensions/libxt_NFQUEUE.txlate @@ -1,8 +1,8 @@ iptables-translate -t nat -A PREROUTING -p tcp --dport 80 -j NFQUEUE --queue-num 30 -nft add rule ip nat PREROUTING tcp dport 80 counter queue num 30 +nft 'add rule ip nat PREROUTING tcp dport 80 counter queue num 30' iptables-translate -A FORWARD -j NFQUEUE --queue-num 0 --queue-bypass -p TCP --sport 80 -nft add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass +nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass' iptables-translate -A FORWARD -j NFQUEUE --queue-bypass -p TCP --sport 80 --queue-balance 0:3 --queue-cpu-fanout -nft add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout +nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout' diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate index 9d35619d..9490ee8f 100644 --- a/extensions/libxt_NOTRACK.txlate +++ b/extensions/libxt_NOTRACK.txlate @@ -1,2 +1,2 @@ iptables-translate -A PREROUTING -t raw -j NOTRACK -nft add rule ip raw PREROUTING counter notrack +nft 'add rule ip raw PREROUTING counter notrack' diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate index 36419a46..dc473340 100644 --- a/extensions/libxt_REDIRECT.txlate +++ b/extensions/libxt_REDIRECT.txlate @@ -1,29 +1,29 @@ iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT -nft add rule ip nat prerouting tcp dport 80 counter redirect +nft 'add rule ip nat prerouting tcp dport 80 counter redirect' iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :0 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0' iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080' iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0-65535 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535' iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :10-22 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :10-22' iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random' iptables-translate -t nat -A prerouting -j REDIRECT --random -nft add rule ip nat prerouting counter redirect random +nft 'add rule ip nat prerouting counter redirect random' ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT -nft add rule ip6 nat prerouting tcp dport 80 counter redirect +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect' ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080' ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random' diff --git a/extensions/libxt_SYNPROXY.txlate b/extensions/libxt_SYNPROXY.txlate index a2a3b6c5..b996c4b7 100644 --- a/extensions/libxt_SYNPROXY.txlate +++ b/extensions/libxt_SYNPROXY.txlate @@ -1,2 +1,2 @@ iptables-translate -t mangle -A INPUT -i iifname -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 -nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460 +nft 'add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460' diff --git a/extensions/libxt_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate index 3dbbad66..a059c602 100644 --- a/extensions/libxt_TCPMSS.txlate +++ b/extensions/libxt_TCPMSS.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu +nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu' iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90 -nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90 +nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90' diff --git a/extensions/libxt_TEE.txlate b/extensions/libxt_TEE.txlate index 9fcee254..fa1d5fe3 100644 --- a/extensions/libxt_TEE.txlate +++ b/extensions/libxt_TEE.txlate @@ -1,11 +1,11 @@ # iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 --oif eth0 -# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0 +# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0 # # iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 -# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 +# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2 ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: -nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: +nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba::' ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: --oif eth0 -nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0 +nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0' diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate index 9c126742..37ef1d86 100644 --- a/extensions/libxt_TOS.txlate +++ b/extensions/libxt_TOS.txlate @@ -1,26 +1,26 @@ ip6tables-translate -A INPUT -j TOS --set-tos 0x1f -nft add rule ip6 filter INPUT counter ip6 dscp set 0x07 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x07' ip6tables-translate -A INPUT -j TOS --set-tos 0xff -nft add rule ip6 filter INPUT counter ip6 dscp set 0x3f +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x3f' ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Delay -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x04' ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Cost -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00' ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00' ip6tables-translate -A INPUT -j TOS --and-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04' ip6tables-translate -A INPUT -j TOS --or-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04' ip6tables-translate -A INPUT -j TOS --xor-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04' ip6tables-translate -A INPUT -j TOS --set-tos 0x12/0x34 -nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04' diff --git a/extensions/libxt_TRACE.txlate b/extensions/libxt_TRACE.txlate index 8e3d2a7a..a9d28fe0 100644 --- a/extensions/libxt_TRACE.txlate +++ b/extensions/libxt_TRACE.txlate @@ -1,2 +1,2 @@ iptables-translate -t raw -A PREROUTING -j TRACE -nft add rule ip raw PREROUTING counter nftrace set 1 +nft 'add rule ip raw PREROUTING counter nftrace set 1' diff --git a/extensions/libxt_addrtype.txlate b/extensions/libxt_addrtype.txlate index a719b2c9..70c0a345 100644 --- a/extensions/libxt_addrtype.txlate +++ b/extensions/libxt_addrtype.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -m addrtype --src-type LOCAL -nft add rule ip filter INPUT fib saddr type local counter +nft 'add rule ip filter INPUT fib saddr type local counter' iptables-translate -A INPUT -m addrtype --dst-type LOCAL -nft add rule ip filter INPUT fib daddr type local counter +nft 'add rule ip filter INPUT fib daddr type local counter' iptables-translate -A INPUT -m addrtype ! --dst-type ANYCAST,LOCAL -nft add rule ip filter INPUT fib daddr type != { local, anycast } counter +nft 'add rule ip filter INPUT fib daddr type != { local, anycast } counter' iptables-translate -A INPUT -m addrtype --limit-iface-in --dst-type ANYCAST,LOCAL -nft add rule ip filter INPUT fib daddr . iif type { local, anycast } counter +nft 'add rule ip filter INPUT fib daddr . iif type { local, anycast } counter' diff --git a/extensions/libxt_cgroup.txlate b/extensions/libxt_cgroup.txlate index 75f2e6ae..6e3aab76 100644 --- a/extensions/libxt_cgroup.txlate +++ b/extensions/libxt_cgroup.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m cgroup --cgroup 0 -j ACCEPT -nft add rule ip filter INPUT meta cgroup 0 counter accept +nft 'add rule ip filter INPUT meta cgroup 0 counter accept' iptables-translate -t filter -A INPUT -m cgroup ! --cgroup 0 -j ACCEPT -nft add rule ip filter INPUT meta cgroup != 0 counter accept +nft 'add rule ip filter INPUT meta cgroup != 0 counter accept' diff --git a/extensions/libxt_cluster.txlate b/extensions/libxt_cluster.txlate index 9dcf5707..4dc1c691 100644 --- a/extensions/libxt_cluster.txlate +++ b/extensions/libxt_cluster.txlate @@ -1,26 +1,26 @@ iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-node 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-nodemask 9 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-node 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff' diff --git a/extensions/libxt_comment.txlate b/extensions/libxt_comment.txlate index c610b0e5..5d4ce59d 100644 --- a/extensions/libxt_comment.txlate +++ b/extensions/libxt_comment.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -s 192.168.0.0 -m comment --comment "A privatized IP block" -nft add rule ip filter INPUT ip saddr 192.168.0.0 counter comment \"A privatized IP block\" +nft 'add rule ip filter INPUT ip saddr 192.168.0.0 counter comment "A privatized IP block"' iptables-translate -A INPUT -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j LONGNACCEPT -m comment --comment "foobar" -nft add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment \"foobar\" +nft 'add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment "foobar"' iptables-translate -A FORWARD -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j DROP -m comment --comment singlecomment -nft add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment \"singlecomment\" +nft 'add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment "singlecomment"' diff --git a/extensions/libxt_connbytes.txlate b/extensions/libxt_connbytes.txlate index f78958d2..a6af1b87 100644 --- a/extensions/libxt_connbytes.txlate +++ b/extensions/libxt_connbytes.txlate @@ -1,14 +1,14 @@ iptables-translate -A OUTPUT -m connbytes --connbytes 200 --connbytes-dir original --connbytes-mode packets -nft add rule ip filter OUTPUT ct original packets ge 200 counter +nft 'add rule ip filter OUTPUT ct original packets ge 200 counter' iptables-translate -A OUTPUT -m connbytes ! --connbytes 200 --connbytes-dir reply --connbytes-mode packets -nft add rule ip filter OUTPUT ct reply packets lt 200 counter +nft 'add rule ip filter OUTPUT ct reply packets lt 200 counter' iptables-translate -A OUTPUT -m connbytes --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes -nft add rule ip filter OUTPUT ct bytes 200-600 counter +nft 'add rule ip filter OUTPUT ct bytes 200-600 counter' iptables-translate -A OUTPUT -m connbytes ! --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes -nft add rule ip filter OUTPUT ct bytes != 200-600 counter +nft 'add rule ip filter OUTPUT ct bytes != 200-600 counter' iptables-translate -A OUTPUT -m connbytes --connbytes 200:200 --connbytes-dir both --connbytes-mode avgpkt -nft add rule ip filter OUTPUT ct avgpkt 200 counter +nft 'add rule ip filter OUTPUT ct avgpkt 200 counter' diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate index 12e4ac03..cba01d2d 100644 --- a/extensions/libxt_connlabel.txlate +++ b/extensions/libxt_connlabel.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m connlabel --label 40 -nft add rule ip filter INPUT ct label 40 counter +nft 'add rule ip filter INPUT ct label 40 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 +nft 'add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter' diff --git a/extensions/libxt_connlimit.txlate b/extensions/libxt_connlimit.txlate index 758868c4..3108a529 100644 --- a/extensions/libxt_connlimit.txlate +++ b/extensions/libxt_connlimit.txlate @@ -1,15 +1,15 @@ iptables-translate -A INPUT -m connlimit --connlimit-above 2 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-mask 24 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-daddr -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter' diff --git a/extensions/libxt_connmark.txlate b/extensions/libxt_connmark.txlate index 89423259..e7bfd721 100644 --- a/extensions/libxt_connmark.txlate +++ b/extensions/libxt_connmark.txlate @@ -1,14 +1,14 @@ iptables-translate -A INPUT -m connmark --mark 2 -j ACCEPT -nft add rule ip filter INPUT ct mark 0x2 counter accept +nft 'add rule ip filter INPUT ct mark 0x2 counter accept' iptables-translate -A INPUT -m connmark ! --mark 2 -j ACCEPT -nft add rule ip filter INPUT ct mark != 0x2 counter accept +nft 'add rule ip filter INPUT ct mark != 0x2 counter accept' iptables-translate -A INPUT -m connmark --mark 10/10 -j ACCEPT -nft add rule ip filter INPUT ct mark and 0xa == 0xa counter accept +nft 'add rule ip filter INPUT ct mark and 0xa == 0xa counter accept' iptables-translate -A INPUT -m connmark ! --mark 10/10 -j ACCEPT -nft add rule ip filter INPUT ct mark and 0xa != 0xa counter accept +nft 'add rule ip filter INPUT ct mark and 0xa != 0xa counter accept' iptables-translate -t mangle -A PREROUTING -p tcp --dport 40 -m connmark --mark 0x40 -nft add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter +nft 'add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter' diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index 45fba984..0f44a957 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -1,60 +1,60 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCEPT -nft add rule ip filter INPUT ct state new,related counter accept +nft 'add rule ip filter INPUT ct state new,related counter accept' ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT -nft add rule ip6 filter INPUT ct state ! new,related counter accept +nft 'add rule ip6 filter INPUT ct state ! new,related counter accept' ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT -nft add rule ip6 filter INPUT ct state ! new counter accept +nft 'add rule ip6 filter INPUT ct state ! new counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT -nft add rule ip filter INPUT ct original protocol 17 counter accept +nft 'add rule ip filter INPUT ct original protocol 17 counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctproto UDP -j ACCEPT -nft add rule ip filter INPUT ct original protocol != 17 counter accept +nft 'add rule ip filter INPUT ct original protocol != 17 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.0.0/255.255.0.0 -j ACCEPT -nft add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept +nft 'add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigdst 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctreplsrc 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctrepldst 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctproto tcp --ctorigsrcport 443:444 -j ACCEPT -nft add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept +nft 'add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT -nft add rule ip filter INPUT ct status expected counter accept +nft 'add rule ip filter INPUT ct status expected counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT -nft add rule ip filter INPUT ct status ! confirmed counter accept +nft 'add rule ip filter INPUT ct status ! confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT -nft add rule ip filter INPUT ct status ! assured,confirmed counter accept +nft 'add rule ip filter INPUT ct status ! assured,confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT -nft add rule ip filter INPUT ct status assured,confirmed counter accept +nft 'add rule ip filter INPUT ct status assured,confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT -nft add rule ip filter INPUT ct expiration 3 counter accept +nft 'add rule ip filter INPUT ct expiration 3 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctdir ORIGINAL -j ACCEPT -nft add rule ip filter INPUT ct direction original counter accept +nft 'add rule ip filter INPUT ct direction original counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT -nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept +nft 'add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT -nft add rule ip filter INPUT ct status snat counter accept +nft 'add rule ip filter INPUT ct status snat counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT -nft add rule ip filter INPUT ct status dnat counter accept +nft 'add rule ip filter INPUT ct status dnat counter accept' diff --git a/extensions/libxt_cpu.txlate b/extensions/libxt_cpu.txlate index c59b0e02..937c939e 100644 --- a/extensions/libxt_cpu.txlate +++ b/extensions/libxt_cpu.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -p tcp --dport 80 -m cpu --cpu 0 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 cpu 0 counter accept +nft 'add rule ip filter INPUT tcp dport 80 cpu 0 counter accept' iptables-translate -A INPUT -p tcp --dport 80 -m cpu ! --cpu 1 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept +nft 'add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept' diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate index be950bcb..a4da1a79 100644 --- a/extensions/libxt_dccp.txlate +++ b/extensions/libxt_dccp.txlate @@ -1,20 +1,20 @@ iptables-translate -A INPUT -p dccp -m dccp --sport 100 -nft add rule ip filter INPUT dccp sport 100 counter +nft 'add rule ip filter INPUT dccp sport 100 counter' iptables-translate -A INPUT -p dccp -m dccp --dport 100:200 -nft add rule ip filter INPUT dccp dport 100-200 counter +nft 'add rule ip filter INPUT dccp dport 100-200 counter' iptables-translate -A INPUT -p dccp -m dccp ! --dport 100 -nft add rule ip filter INPUT dccp dport != 100 counter +nft 'add rule ip filter INPUT dccp dport != 100 counter' iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE -nft add rule ip filter INPUT dccp type close counter +nft 'add rule ip filter INPUT dccp type close counter' iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID -nft add rule ip filter INPUT dccp type 10-15 counter +nft 'add rule ip filter INPUT dccp type 10-15 counter' iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID -nft add rule ip filter INPUT dccp dport 100 dccp type { request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15 } counter +nft 'add rule ip filter INPUT dccp dport 100 dccp type { request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15 } counter' iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100 -nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter +nft 'add rule ip filter INPUT dccp sport 200 dccp dport 100 counter' diff --git a/extensions/libxt_devgroup.txlate b/extensions/libxt_devgroup.txlate index aeb597bd..dea47a99 100644 --- a/extensions/libxt_devgroup.txlate +++ b/extensions/libxt_devgroup.txlate @@ -1,17 +1,17 @@ iptables-translate -A FORWARD -m devgroup --src-group 0x2 -j ACCEPT -nft add rule ip filter FORWARD iifgroup 0x2 counter accept +nft 'add rule ip filter FORWARD iifgroup 0x2 counter accept' iptables-translate -A FORWARD -m devgroup --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept +nft 'add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept' iptables-translate -t mangle -A PREROUTING -p tcp --dport 46000 -m devgroup --src-group 23 -j ACCEPT -nft add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept +nft 'add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept' iptables-translate -A FORWARD -m devgroup ! --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept +nft 'add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept' iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 -j ACCEPT -nft add rule ip filter FORWARD iifgroup != 0x2 counter accept +nft 'add rule ip filter FORWARD iifgroup != 0x2 counter accept' iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept +nft 'add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept' diff --git a/extensions/libxt_dscp.txlate b/extensions/libxt_dscp.txlate index 2cccc3b4..ca2ec724 100644 --- a/extensions/libxt_dscp.txlate +++ b/extensions/libxt_dscp.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m dscp --dscp 0x32 -j ACCEPT -nft add rule ip filter INPUT ip dscp 0x32 counter accept +nft 'add rule ip filter INPUT ip dscp 0x32 counter accept' ip6tables-translate -t filter -A INPUT -m dscp ! --dscp 0x32 -j ACCEPT -nft add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept +nft 'add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept' diff --git a/extensions/libxt_ecn.txlate b/extensions/libxt_ecn.txlate index f012f128..8488f8ce 100644 --- a/extensions/libxt_ecn.txlate +++ b/extensions/libxt_ecn.txlate @@ -1,29 +1,29 @@ iptables-translate -A INPUT -m ecn --ecn-ip-ect 0 -nft add rule ip filter INPUT ip ecn not-ect counter +nft 'add rule ip filter INPUT ip ecn not-ect counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 1 -nft add rule ip filter INPUT ip ecn ect1 counter +nft 'add rule ip filter INPUT ip ecn ect1 counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 2 -nft add rule ip filter INPUT ip ecn ect0 counter +nft 'add rule ip filter INPUT ip ecn ect0 counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 3 -nft add rule ip filter INPUT ip ecn ce counter +nft 'add rule ip filter INPUT ip ecn ce counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 0 -nft add rule ip filter INPUT ip ecn != not-ect counter +nft 'add rule ip filter INPUT ip ecn != not-ect counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 1 -nft add rule ip filter INPUT ip ecn != ect1 counter +nft 'add rule ip filter INPUT ip ecn != ect1 counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 2 -nft add rule ip filter INPUT ip ecn != ect0 counter +nft 'add rule ip filter INPUT ip ecn != ect0 counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 3 -nft add rule ip filter INPUT ip ecn != ce counter +nft 'add rule ip filter INPUT ip ecn != ce counter' iptables-translate -A INPUT -m ecn ! --ecn-tcp-ece -nft add rule ip filter INPUT tcp flags != ecn counter +nft 'add rule ip filter INPUT tcp flags != ecn counter' iptables-translate -A INPUT -m ecn --ecn-tcp-cwr -nft add rule ip filter INPUT tcp flags cwr counter +nft 'add rule ip filter INPUT tcp flags cwr counter' diff --git a/extensions/libxt_esp.txlate b/extensions/libxt_esp.txlate index 5e2f18fa..f6aba52f 100644 --- a/extensions/libxt_esp.txlate +++ b/extensions/libxt_esp.txlate @@ -1,11 +1,11 @@ iptables-translate -A FORWARD -p esp -j ACCEPT -nft add rule ip filter FORWARD ip protocol esp counter accept +nft 'add rule ip filter FORWARD ip protocol esp counter accept' iptables-translate -A INPUT --in-interface wan --protocol esp -j ACCEPT -nft add rule ip filter INPUT iifname "wan" ip protocol esp counter accept +nft 'add rule ip filter INPUT iifname "wan" ip protocol esp counter accept' iptables-translate -A INPUT -p 50 -m esp --espspi 500 -j DROP -nft add rule ip filter INPUT esp spi 500 counter drop +nft 'add rule ip filter INPUT esp spi 500 counter drop' iptables-translate -A INPUT -p 50 -m esp --espspi 500:600 -j DROP -nft add rule ip filter INPUT esp spi 500-600 counter drop +nft 'add rule ip filter INPUT esp spi 500-600 counter drop' diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate index 4cc26868..306ee783 100644 --- a/extensions/libxt_hashlimit.txlate +++ b/extensions/libxt_hashlimit.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop +nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop' iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop +nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop' diff --git a/extensions/libxt_helper.txlate b/extensions/libxt_helper.txlate index 8259aba3..2d94f740 100644 --- a/extensions/libxt_helper.txlate +++ b/extensions/libxt_helper.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -m helper --helper sip -nft add rule ip filter FORWARD ct helper \"sip\" counter +nft 'add rule ip filter FORWARD ct helper "sip" counter' iptables-translate -A FORWARD -m helper ! --helper ftp -nft add rule ip filter FORWARD ct helper != \"ftp\" counter +nft 'add rule ip filter FORWARD ct helper != "ftp" counter' diff --git a/extensions/libxt_ipcomp.txlate b/extensions/libxt_ipcomp.txlate index f9efe53c..877cccbb 100644 --- a/extensions/libxt_ipcomp.txlate +++ b/extensions/libxt_ipcomp.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m ipcomp --ipcompspi 0x12 -j ACCEPT -nft add rule ip filter INPUT comp cpi 18 counter accept +nft 'add rule ip filter INPUT comp cpi 18 counter accept' iptables-translate -t filter -A INPUT -m ipcomp ! --ipcompspi 0x12 -j ACCEPT -nft add rule ip filter INPUT comp cpi != 18 counter accept +nft 'add rule ip filter INPUT comp cpi != 18 counter accept' diff --git a/extensions/libxt_iprange.txlate b/extensions/libxt_iprange.txlate index 999f4b72..80369650 100644 --- a/extensions/libxt_iprange.txlate +++ b/extensions/libxt_iprange.txlate @@ -1,14 +1,14 @@ iptables-translate -A INPUT -m iprange --src-range 192.168.25.149-192.168.25.151 -j ACCEPT -nft add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept +nft 'add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept' iptables-translate -A INPUT -m iprange --dst-range 192.168.25.149-192.168.25.151 -j ACCEPT -nft add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept +nft 'add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept' iptables-translate -A INPUT -m iprange --dst-range 3.3.3.3-6.6.6.6 --src-range 4.4.4.4-7.7.7.7 -j ACCEPT -nft add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept +nft 'add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept' ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 -j ACCEPT -nft add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept +nft 'add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept' ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 --src-range ::2d01-::2d03 -j ACCEPT -nft add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept +nft 'add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept' diff --git a/extensions/libxt_length.txlate b/extensions/libxt_length.txlate index e777c265..38f835dc 100644 --- a/extensions/libxt_length.txlate +++ b/extensions/libxt_length.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -p icmp -m length --length 86:0xffff -j DROP -nft add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop +nft 'add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop' iptables-translate -A INPUT -p udp -m length --length :400 -nft add rule ip filter INPUT ip protocol udp meta length 0-400 counter +nft 'add rule ip filter INPUT ip protocol udp meta length 0-400 counter' iptables-translate -A INPUT -p udp -m length --length 40 -nft add rule ip filter INPUT ip protocol udp meta length 40 counter +nft 'add rule ip filter INPUT ip protocol udp meta length 40 counter' iptables-translate -A INPUT -p udp -m length ! --length 40 -nft add rule ip filter INPUT ip protocol udp meta length != 40 counter +nft 'add rule ip filter INPUT ip protocol udp meta length != 40 counter' diff --git a/extensions/libxt_limit.txlate b/extensions/libxt_limit.txlate index df9ed2d5..fa8e1bc0 100644 --- a/extensions/libxt_limit.txlate +++ b/extensions/libxt_limit.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -m limit --limit 3/m --limit-burst 3 -nft add rule ip filter INPUT limit rate 3/minute burst 3 packets counter +nft 'add rule ip filter INPUT limit rate 3/minute burst 3 packets counter' iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 5 -nft add rule ip filter INPUT limit rate 10/second burst 5 packets counter +nft 'add rule ip filter INPUT limit rate 10/second burst 5 packets counter' iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 0 -nft add rule ip filter INPUT limit rate 10/second counter +nft 'add rule ip filter INPUT limit rate 10/second counter' diff --git a/extensions/libxt_mac.txlate b/extensions/libxt_mac.txlate index 08696f3d..16800179 100644 --- a/extensions/libxt_mac.txlate +++ b/extensions/libxt_mac.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m mac --mac-source 0a:12:3e:4f:b2:c6 -j DROP -nft add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop +nft 'add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop' iptables-translate -A INPUT -p tcp --dport 80 -m mac --mac-source 0a:12:3e:4f:b2:c6 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept +nft 'add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept' diff --git a/extensions/libxt_mark.txlate b/extensions/libxt_mark.txlate index 6bfb5243..6e097091 100644 --- a/extensions/libxt_mark.txlate +++ b/extensions/libxt_mark.txlate @@ -1,5 +1,5 @@ iptables-translate -I INPUT -p tcp -m mark ! --mark 0xa/0xa -nft insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter +nft 'insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter' iptables-translate -I INPUT -p tcp -m mark ! --mark 0x1 -nft insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter +nft 'insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter' diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate index 4f0c9c02..aa5f006d 100644 --- a/extensions/libxt_multiport.txlate +++ b/extensions/libxt_multiport.txlate @@ -1,14 +1,14 @@ iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport { 80, 81 } counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport { 80, 81 } counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport ! --dports 80:88 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept' iptables-translate -t filter -I INPUT -p tcp -m multiport --ports 10 -nft insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter +nft 'insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter' diff --git a/extensions/libxt_owner.txlate b/extensions/libxt_owner.txlate index 86fb0585..8fbd68eb 100644 --- a/extensions/libxt_owner.txlate +++ b/extensions/libxt_owner.txlate @@ -1,8 +1,8 @@ iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner root -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept' iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --gid-owner 0-10 -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept' iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner 1000 -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept' diff --git a/extensions/libxt_pkttype.txlate b/extensions/libxt_pkttype.txlate index 6506a380..c69f56f9 100644 --- a/extensions/libxt_pkttype.txlate +++ b/extensions/libxt_pkttype.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -m pkttype --pkt-type broadcast -j DROP -nft add rule ip filter INPUT pkttype broadcast counter drop +nft 'add rule ip filter INPUT pkttype broadcast counter drop' iptables-translate -A INPUT -m pkttype ! --pkt-type unicast -j DROP -nft add rule ip filter INPUT pkttype != unicast counter drop +nft 'add rule ip filter INPUT pkttype != unicast counter drop' iptables-translate -A INPUT -m pkttype --pkt-type multicast -j ACCEPT -nft add rule ip filter INPUT pkttype multicast counter accept +nft 'add rule ip filter INPUT pkttype multicast counter accept' diff --git a/extensions/libxt_policy.txlate b/extensions/libxt_policy.txlate index 66788a76..a960b395 100644 --- a/extensions/libxt_policy.txlate +++ b/extensions/libxt_policy.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m policy --pol ipsec --dir in -nft add rule ip filter INPUT meta secpath exists counter +nft 'add rule ip filter INPUT meta secpath exists counter' iptables-translate -A INPUT -m policy --pol none --dir in -nft add rule ip filter INPUT meta secpath missing counter +nft 'add rule ip filter INPUT meta secpath missing counter' diff --git a/extensions/libxt_quota.txlate b/extensions/libxt_quota.txlate index 91142141..6edd925d 100644 --- a/extensions/libxt_quota.txlate +++ b/extensions/libxt_quota.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m quota --quota 111 -nft add rule ip filter OUTPUT quota 111 bytes counter +nft 'add rule ip filter OUTPUT quota 111 bytes counter' iptables-translate -A OUTPUT -m quota ! --quota 111 -nft add rule ip filter OUTPUT quota over 111 bytes counter +nft 'add rule ip filter OUTPUT quota over 111 bytes counter' diff --git a/extensions/libxt_rpfilter.txlate b/extensions/libxt_rpfilter.txlate index 8d7733ba..a551c419 100644 --- a/extensions/libxt_rpfilter.txlate +++ b/extensions/libxt_rpfilter.txlate @@ -1,8 +1,8 @@ iptables-translate -t mangle -A PREROUTING -m rpfilter -nft add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter +nft 'add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter' iptables-translate -t mangle -A PREROUTING -m rpfilter --validmark --loose -nft add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter +nft 'add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter' ip6tables-translate -t mangle -A PREROUTING -m rpfilter --validmark --invert -nft add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter +nft 'add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter' diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate index 6443abf9..0aa7371d 100644 --- a/extensions/libxt_sctp.txlate +++ b/extensions/libxt_sctp.txlate @@ -1,44 +1,44 @@ iptables-translate -A INPUT -p sctp --dport 80 -j DROP -nft add rule ip filter INPUT sctp dport 80 counter drop +nft 'add rule ip filter INPUT sctp dport 80 counter drop' iptables-translate -A INPUT -p sctp --sport 50 -j DROP -nft add rule ip filter INPUT sctp sport 50 counter drop +nft 'add rule ip filter INPUT sctp sport 50 counter drop' iptables-translate -A INPUT -p sctp ! --dport 80 -j DROP -nft add rule ip filter INPUT sctp dport != 80 counter drop +nft 'add rule ip filter INPUT sctp dport != 80 counter drop' iptables-translate -A INPUT -p sctp ! --sport 50 -j DROP -nft add rule ip filter INPUT sctp sport != 50 counter drop +nft 'add rule ip filter INPUT sctp sport != 50 counter drop' iptables-translate -A INPUT -p sctp --sport 80:100 -j ACCEPT -nft add rule ip filter INPUT sctp sport 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 50:56 -j ACCEPT -nft add rule ip filter INPUT sctp dport 50-56 counter accept +nft 'add rule ip filter INPUT sctp dport 50-56 counter accept' iptables-translate -A INPUT -p sctp ! --sport 80:100 -j ACCEPT -nft add rule ip filter INPUT sctp sport != 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport != 80-100 counter accept' iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT -nft add rule ip filter INPUT sctp dport != 50-56 counter accept +nft 'add rule ip filter INPUT sctp dport != 50-56 counter accept' iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT -nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept +nft 'add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept' iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT -nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk i-data missing sctp chunk re-config missing sctp chunk pad missing sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing sctp chunk i-forward-tsn missing counter accept +nft 'add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk i-data missing sctp chunk re-config missing sctp chunk pad missing sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing sctp chunk i-forward-tsn missing counter accept' diff --git a/extensions/libxt_statistic.txlate b/extensions/libxt_statistic.txlate index 4c3dea43..3196ff20 100644 --- a/extensions/libxt_statistic.txlate +++ b/extensions/libxt_statistic.txlate @@ -1,8 +1,8 @@ iptables-translate -A OUTPUT -m statistic --mode nth --every 10 --packet 1 -nft add rule ip filter OUTPUT numgen inc mod 10 1 counter +nft 'add rule ip filter OUTPUT numgen inc mod 10 1 counter' iptables-translate -A OUTPUT -m statistic --mode nth ! --every 10 --packet 5 -nft add rule ip filter OUTPUT numgen inc mod 10 != 5 counter +nft 'add rule ip filter OUTPUT numgen inc mod 10 != 5 counter' iptables-translate -A OUTPUT -m statistic --mode random --probability 0.1 nft # -A OUTPUT -m statistic --mode random --probability 0.1 diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate index a1f0e909..9802ddfe 100644 --- a/extensions/libxt_tcp.txlate +++ b/extensions/libxt_tcp.txlate @@ -1,32 +1,32 @@ iptables-translate -A INPUT -p tcp -i eth0 --sport 53 -j ACCEPT -nft add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept +nft 'add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept' iptables-translate -A OUTPUT -p tcp -o eth0 --dport 53:66 -j DROP -nft add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop +nft 'add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop' iptables-translate -I OUTPUT -p tcp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept' iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT -nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept +nft 'insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept' iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP -nft add rule ip filter INPUT tcp flags fin / fin,ack counter drop +nft 'add rule ip filter INPUT tcp flags fin / fin,ack counter drop' iptables-translate -A INPUT -p tcp --syn -j ACCEPT -nft add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept +nft 'add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept' iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept +nft 'add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept' iptables-translate -A INPUT -f -p tcp -nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter +nft 'add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter' iptables-translate -A INPUT ! -f -p tcp --dport 22 -nft add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter +nft 'add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter' iptables-translate -A INPUT -p tcp --tcp-option 23 -nft add rule ip filter INPUT tcp option 23 exists counter +nft 'add rule ip filter INPUT tcp option 23 exists counter' iptables-translate -A INPUT -p tcp ! --tcp-option 23 -nft add rule ip filter INPUT tcp option 23 missing counter +nft 'add rule ip filter INPUT tcp option 23 missing counter' diff --git a/extensions/libxt_tcpmss.txlate b/extensions/libxt_tcpmss.txlate index d3f1b27d..82475e67 100644 --- a/extensions/libxt_tcpmss.txlate +++ b/extensions/libxt_tcpmss.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -m tcpmss --mss 42 -nft add rule ip filter INPUT tcp option maxseg size 42 counter +nft 'add rule ip filter INPUT tcp option maxseg size 42 counter' iptables-translate -A INPUT -m tcpmss ! --mss 42 -nft add rule ip filter INPUT tcp option maxseg size != 42 counter +nft 'add rule ip filter INPUT tcp option maxseg size != 42 counter' iptables-translate -A INPUT -m tcpmss --mss 42:1024 -nft add rule ip filter INPUT tcp option maxseg size 42-1024 counter +nft 'add rule ip filter INPUT tcp option maxseg size 42-1024 counter' iptables-translate -A INPUT -m tcpmss ! --mss 1461:65535 -nft add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter +nft 'add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter' diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate index 5577c6ca..ed64b957 100644 --- a/extensions/libxt_time.txlate +++ b/extensions/libxt_time.txlate @@ -1,26 +1,26 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta day { 6, 0 } counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta day { 6, 0 } counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021-01-29T00:00:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1, 2, 3, 4, 5 } counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1, 2, 3, 4, 5 } counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6, 0 } counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6, 0 } counter reject' diff --git a/extensions/libxt_udp.txlate b/extensions/libxt_udp.txlate index fbca5c12..28e7ca20 100644 --- a/extensions/libxt_udp.txlate +++ b/extensions/libxt_udp.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT -nft add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept +nft 'add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept' iptables-translate -A OUTPUT -p udp -o eth0 --dport 53:66 -j DROP -nft add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop +nft 'add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop' iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept' iptables-translate -I OUTPUT -p udp --dport 1020:1023 --sport 53 -j ACCEPT -nft insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept +nft 'insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept' -- cgit v1.2.3 From fb421f13ff411fa83467bae5283194a0a583cf38 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 30 Nov 2022 10:31:54 +0100 Subject: xlate-test: avoid shell entanglements Feed the nft expected output found in the .txlate test files to nft -f via pipe/stdin directly without the shell mangling it. The shell step isn't needed anymore because xtables-translate no longer escapes quotes. We only need to remove the "nft '" and trailing "'" because nft doesn't expect those. v3: handle multi-line expectations such as libxt_connlimmit.txlate (Phil Sutter) Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- xlate-test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index f3fcd797..6513b314 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -7,11 +7,11 @@ import shlex import argparse from subprocess import Popen, PIPE -def run_proc(args, shell = False): +def run_proc(args, shell = False, input = None): """A simple wrapper around Popen, returning (rc, stdout, stderr)""" process = Popen(args, text = True, shell = shell, - stdout = PIPE, stderr = PIPE) - output, error = process.communicate() + stdin = PIPE, stdout = PIPE, stderr = PIPE) + output, error = process.communicate(input) return (process.returncode, output, error) keywords = ("iptables-translate", "ip6tables-translate", "ebtables-translate") @@ -100,15 +100,15 @@ def test_one_replay(name, sourceline, expected, result): fam = "ip6 " elif srccmd.startswith("ebt"): fam = "bridge " + + expected = [ l.removeprefix("nft ").strip(" '") for l in expected.split("\n") ] nft_input = [ "flush ruleset", "add table " + fam + table_name, - "add chain " + fam + table_name + " " + chain_name - ] + [ l.removeprefix("nft ") for l in expected.split("\n") ] + "add chain " + fam + table_name + " " + chain_name, + ] + expected - # feed input via the pipe to make sure the shell "does its thing" - cmd = "echo \"" + "\n".join(nft_input) + "\" | " + args.nft + " -f -" - rc, output, error = run_proc(cmd, shell = True) + rc, output, error = run_proc([args.nft, "-f", "-"], shell = False, input = "\n".join(nft_input)) if rc != 0: result.append(name + ": " + red("Fail")) result.append(args.nft + " call failed: " + error.rstrip('\n')) @@ -130,7 +130,7 @@ def test_one_replay(name, sourceline, expected, result): output = l break result.append(name + ": " + red("Replay fail")) - result.append(magenta("src: '") + expected + "'") + result.append(magenta("src: '") + str(expected) + "'") result.append(magenta("exp: '") + searchline + "'") for l in output.split('\n'): result.append(magenta("res: ") + l) -- cgit v1.2.3 From 7f9a0204683f292f05577cd8b4dfc689cdd8e660 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 30 Nov 2022 11:38:12 +0100 Subject: nft-bridge: work around recent "among" decode breakage ebtables-nft-save will fail with "unknown meta key" when decoding "among" emulation with ipv4 or ipv6 addresses included. This is because "meta protocol ip" is used as a dependency, but its never decoded anywhere. Skip this for now to restore the "ebtables/0006-flush_0" test case. Fixes: 25883ce88bfb ("nft: check for unknown meta keys") Signed-off-by: Florian Westphal Acked-by: Phil Sutter --- iptables/nft-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 15dfc585..8d002c17 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -197,6 +197,11 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; + switch (reg->meta_dreg.key) { + case NFT_META_PROTOCOL: + return; + } + if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { ctx->errmsg = "unknown meta key"; return; -- cgit v1.2.3 From 1b1eb7e784a66882d6d4b0440b716b6aba8c99da Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 1 Dec 2022 11:13:17 +0100 Subject: extensions: add xt_statistics random mode translation Use meta random and bitops to replicate what xt_statistics is doing. Signed-off-by: Florian Westphal --- extensions/libxt_statistic.c | 8 +++++++- extensions/libxt_statistic.txlate | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_statistic.c b/extensions/libxt_statistic.c index 4f3341a3..37915adc 100644 --- a/extensions/libxt_statistic.c +++ b/extensions/libxt_statistic.c @@ -141,13 +141,19 @@ static int statistic_xlate(struct xt_xlate *xl, switch (info->mode) { case XT_STATISTIC_MODE_RANDOM: - return 0; + xt_xlate_add(xl, "meta random & %u %s %u", + INT_MAX, + info->flags & XT_STATISTIC_INVERT ? ">=" : "<", + info->u.random.probability); + break; case XT_STATISTIC_MODE_NTH: xt_xlate_add(xl, "numgen inc mod %u %s%u", info->u.nth.every + 1, info->flags & XT_STATISTIC_INVERT ? "!= " : "", info->u.nth.packet); break; + default: + return 0; } return 1; diff --git a/extensions/libxt_statistic.txlate b/extensions/libxt_statistic.txlate index 3196ff20..627120c5 100644 --- a/extensions/libxt_statistic.txlate +++ b/extensions/libxt_statistic.txlate @@ -5,4 +5,4 @@ iptables-translate -A OUTPUT -m statistic --mode nth ! --every 10 --packet 5 nft 'add rule ip filter OUTPUT numgen inc mod 10 != 5 counter' iptables-translate -A OUTPUT -m statistic --mode random --probability 0.1 -nft # -A OUTPUT -m statistic --mode random --probability 0.1 +nft 'add rule ip filter OUTPUT meta random & 2147483647 < 214748365 counter' -- cgit v1.2.3 From 072d15dfed9c1c15fbf4273f31a0226faab996f7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Nov 2022 17:58:13 +0100 Subject: tests: shell: Fix valgrind mode for 0008-unprivileged_0 Valgrind is run as user nobody, let everyone write into the temporary directory. Signed-off-by: Phil Sutter --- iptables/tests/shell/run-tests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index 7878760f..7a80af34 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -122,7 +122,8 @@ EOF if [ "$VALGRIND" == "y" ]; then tmpd=$(mktemp -d) msg_info "writing valgrind logs to $tmpd" - chmod a+rx $tmpd + # let nobody write logs, too (././testcases/iptables/0008-unprivileged_0) + chmod 777 $tmpd printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi trap "rm ${tmpd}/xtables-*-multi" EXIT -- cgit v1.2.3 From 18880dbde615449d00a3e38f3713a19d4566258e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 19:24:38 +0100 Subject: iptables-restore: Free handle with --test also When running 'iptables-restore -t', valgrind reports: 1,496 (160 direct, 1,336 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4 at 0x48417E5: malloc (vg_replace_malloc.c:381) by 0x4857A46: alloc_handle (libiptc.c:1279) by 0x4857A46: iptc_init (libiptc.c:1342) by 0x1167CE: create_handle (iptables-restore.c:72) by 0x1167CE: ip46tables_restore_main (iptables-restore.c:229) by 0x116DAE: iptables_restore_main (iptables-restore.c:388) by 0x49A2349: (below main) (in /lib64/libc.so.6) Free the handle pointer before parsing the next table. Fixes: 1c9015b2cb483 ("libiptc: remove indirections") Signed-off-by: Phil Sutter --- iptables/iptables-restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 05661bf6..6f7ddf93 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -185,12 +185,12 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, if (!testing) { DEBUGP("Calling commit\n"); ret = cb->ops->commit(handle); - cb->ops->free(handle); - handle = NULL; } else { DEBUGP("Not calling commit, testing\n"); ret = 1; } + cb->ops->free(handle); + handle = NULL; /* Done with the current table, release the lock. */ if (lock >= 0) { -- cgit v1.2.3 From 73da7fb74c1089391dac0aca70e13e5f5999ace7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 19:30:09 +0100 Subject: iptables-xml: Free allocated chain strings Freeing only if 'created' is non-zero is wrong - the data was still allocated. In fact, the field is supposed to prevent only the call to openChain(). Fixes: 8d3eccb19a9c6 ("Add iptables-xml tool (Amin Azez )") Signed-off-by: Phil Sutter --- iptables/iptables-xml.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c index d28cf748..396c0a12 100644 --- a/iptables/iptables-xml.c +++ b/iptables/iptables-xml.c @@ -225,13 +225,13 @@ finishChains(void) { int c; - for (c = 0; c < nextChain; c++) - if (!chains[c].created) { + for (c = 0; c < nextChain; c++) { + if (!chains[c].created) openChain(chains[c].chain, chains[c].policy, &(chains[c].count), '/'); - free(chains[c].chain); - free(chains[c].policy); - } + free(chains[c].chain); + free(chains[c].policy); + } nextChain = 0; } -- cgit v1.2.3 From aa0c54030300441e9fd66c7016d0090f6736d449 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 21:21:22 +0100 Subject: nft: Plug memleak in nft_rule_zero_counters() When zeroing a specific rule, valgrind reports: 40 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x484659F: calloc (vg_replace_malloc.c:1328) by 0x48DE128: xtables_calloc (xtables.c:434) by 0x11C7C6: nft_parse_immediate (nft-shared.c:1071) by 0x11C7C6: nft_rule_to_iptables_command_state (nft-shared.c:1236) by 0x119AF5: nft_rule_zero_counters (nft.c:2877) by 0x11A3CA: nft_prepare (nft.c:3445) by 0x11A7A8: nft_commit (nft.c:3479) by 0x114258: xtables_main.isra.0 (xtables-standalone.c:94) by 0x1142D9: xtables_ip6_main (xtables-standalone.c:118) by 0x49F2349: (below main) (in /lib64/libc.so.6) Have to free the matches/target in populated iptables_command_state object again. While being at it, call the proper family_ops callbacks since this is family-agnostic code. Fixes: a69cc575295ee ("xtables: allow to reset the counters of an existing rule") Signed-off-by: Phil Sutter --- iptables/nft.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 67c5877c..430888e8 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2874,10 +2874,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, goto error; } - nft_rule_to_iptables_command_state(h, r, &cs); - + h->ops->rule_to_cs(h, r, &cs); cs.counters.pcnt = cs.counters.bcnt = 0; new_rule = nft_rule_new(h, chain, table, &cs); + h->ops->clear_cs(&cs); + if (!new_rule) return 1; -- cgit v1.2.3 From fb63f8b7337aa11a667537e6a3b399062ede2eb5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 21:35:28 +0100 Subject: iptables: Plug memleaks in print_firewall() When adding a rule in verbose mode, valgrind prints: 192 bytes in 1 blocks are definitely lost in loss record 1 of 2 at 0x48417E5: malloc (vg_replace_malloc.c:381) by 0x486B158: xtables_malloc (xtables.c:446) by 0x486C1F6: xtables_find_match (xtables.c:826) by 0x10E684: print_match (iptables.c:115) by 0x10E684: print_firewall (iptables.c:169) by 0x10FC0C: print_firewall_line (iptables.c:196) by 0x10FC0C: append_entry (iptables.c:221) by 0x10FC0C: do_command4 (iptables.c:776) by 0x10E45B: iptables_main (iptables-standalone.c:59) by 0x49A2349: (below main) (in /lib64/libc.so.6) 200 bytes in 1 blocks are definitely lost in loss record 2 of 2 at 0x48417E5: malloc (vg_replace_malloc.c:381) by 0x486B158: xtables_malloc (xtables.c:446) by 0x486BBD6: xtables_find_target (xtables.c:956) by 0x10E579: print_firewall (iptables.c:145) by 0x10FC0C: print_firewall_line (iptables.c:196) by 0x10FC0C: append_entry (iptables.c:221) by 0x10FC0C: do_command4 (iptables.c:776) by 0x10E45B: iptables_main (iptables-standalone.c:59) by 0x49A2349: (below main) (in /lib64/libc.so.6) If the match/target was cloned, it needs to be freed. Basically a bug since day 1. Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 6 ++++++ iptables/iptables.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 062b2b15..1d232657 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -122,6 +122,9 @@ print_match(const struct xt_entry_match *m, printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); + + if (match->next == match) + free(match); } else { if (name[0]) printf("UNKNOWN match `%s' ", name); @@ -179,6 +182,9 @@ print_firewall(const struct ip6t_entry *fw, tg->print(&fw->ipv6, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); + + if (target->next == target) + free(target); } else if (t->u.target_size != sizeof(*t)) printf("[%u bytes of unknown target data] ", (unsigned int)(t->u.target_size - sizeof(*t))); diff --git a/iptables/iptables.c b/iptables/iptables.c index 0351b39f..d246198f 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -122,6 +122,9 @@ print_match(const struct xt_entry_match *m, printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); + + if (match->next == match) + free(match); } else { if (name[0]) printf("UNKNOWN match `%s' ", name); @@ -178,6 +181,9 @@ print_firewall(const struct ipt_entry *fw, tg->print(&fw->ip, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); + + if (target->next == target) + free(target); } else if (t->u.target_size != sizeof(*t)) printf("[%u bytes of unknown target data] ", (unsigned int)(t->u.target_size - sizeof(*t))); -- cgit v1.2.3 From 365647ef056828bc3cb56efef12114951fcb730d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 21:42:20 +0100 Subject: xtables: Introduce xtables_clear_iptables_command_state() This is nft_clear_iptables_command_state() but in a location reachable by legacy iptables, too. Changes callers in non-family-specific code to use clear_cs callback instead of directly calling it - ebtables still has a custom variant. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 4 ++-- iptables/nft-ipv4.c | 4 ++-- iptables/nft-ipv6.c | 4 ++-- iptables/nft-shared.c | 14 -------------- iptables/nft-shared.h | 1 - iptables/xshared.c | 17 +++++++++++++++++ iptables/xshared.h | 2 ++ iptables/xtables-translate.c | 2 +- iptables/xtables.c | 2 +- 9 files changed, 27 insertions(+), 23 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 59f100af..d670cbe6 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -490,7 +490,7 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } static bool nft_arp_is_same(const struct iptables_command_state *cs_a, @@ -787,7 +787,7 @@ struct nft_family_ops nft_family_ops_arp = { }, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .parse_target = nft_ipv46_parse_target, .add_entry = nft_arp_add_entry, .delete_entry = nft_arp_delete_entry, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 6c62dd46..42167351 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -247,7 +247,7 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } static void nft_ipv4_save_rule(const struct iptables_command_state *cs, @@ -454,7 +454,7 @@ struct nft_family_ops nft_family_ops_ipv4 = { }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv4_xlate, .add_entry = nft_ipv4_add_entry, .delete_entry = nft_ipv4_delete_entry, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 98c35afa..3a373b7e 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -211,7 +211,7 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } static void nft_ipv6_save_rule(const struct iptables_command_state *cs, @@ -423,7 +423,7 @@ struct nft_family_ops nft_family_ops_ipv6 = { }, .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv6_xlate, .add_entry = nft_ipv6_add_entry, .delete_entry = nft_ipv6_delete_entry, diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 63d25198..f1503b6c 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1293,20 +1293,6 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h, return ret; } -void nft_clear_iptables_command_state(struct iptables_command_state *cs) -{ - xtables_rule_matches_free(&cs->matches); - if (cs->target) { - free(cs->target->t); - cs->target->t = NULL; - - if (cs->target == cs->target->next) { - free(cs->target); - cs->target = NULL; - } - } -} - void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) { const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index e2c3ac7b..07d39131 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -216,7 +216,6 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); -void nft_clear_iptables_command_state(struct iptables_command_state *cs); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); diff --git a/iptables/xshared.c b/iptables/xshared.c index d400dc59..2a894c19 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1356,6 +1356,23 @@ static const char *optstring_lookup(int family) return ""; } +void xtables_clear_iptables_command_state(struct iptables_command_state *cs) +{ + xtables_rule_matches_free(&cs->matches); + if (cs->target) { + free(cs->target->t); + cs->target->t = NULL; + + free(cs->target->udata); + cs->target->udata = NULL; + + if (cs->target == cs->target->next) { + free(cs->target); + cs->target = NULL; + } + } +} + void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs, struct xtables_args *args) diff --git a/iptables/xshared.h b/iptables/xshared.h index bfae4b4e..0ed9f3c2 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -130,6 +130,8 @@ struct iptables_command_state { bool restore; }; +void xtables_clear_iptables_command_state(struct iptables_command_state *cs); + typedef int (*mainfunc_t)(int, char **); struct subcommand { diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 6b71fcef..102973a6 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -334,7 +334,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], exit(1); } - nft_clear_iptables_command_state(&cs); + h->ops->clear_cs(&cs); if (h->family == AF_INET) { free(args.s.addr.v4); diff --git a/iptables/xtables.c b/iptables/xtables.c index 70924176..22d6ea58 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -262,7 +262,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, *table = p.table; - nft_clear_iptables_command_state(&cs); + h->ops->clear_cs(&cs); free(args.s.addr.ptr); free(args.s.mask.ptr); -- cgit v1.2.3 From 8bee0db39f7553589c2cec58cc92ed2eafd2eb57 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 21:44:39 +0100 Subject: iptables: Properly clear iptables_command_state object When adding a rule with a target which defines a udata_size, valgrind prints: 8 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x484659F: calloc (vg_replace_malloc.c:1328) by 0x486B128: xtables_calloc (xtables.c:434) by 0x1128B4: xs_init_target (xshared.c:238) by 0x113CD3: command_jump (xshared.c:877) by 0x114969: do_parse (xshared.c:1644) by 0x10EEB9: do_command4 (iptables.c:691) by 0x10E45B: iptables_main (iptables-standalone.c:59) by 0x49A2349: (below main) (in /lib64/libc.so.6) It is not sufficient to free cs.target->t, so call xtables_clear_iptables_command_state() which takes care of all the details. Fixes: 2dba676b68ef8 ("extensions: support for per-extension instance "global" variable space") Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 3 +-- iptables/iptables.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 1d232657..345af451 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -778,7 +778,6 @@ int do_command6(int argc, char *argv[], char **table, xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { e = generate_entry(&cs.fw6, cs.matches, cs.target->t); - free(cs.target->t); } } @@ -880,7 +879,7 @@ int do_command6(int argc, char *argv[], char **table, if (verbose > 1) dump_entries6(*handle); - xtables_rule_matches_free(&cs.matches); + xtables_clear_iptables_command_state(&cs); if (e != NULL) { free(e); diff --git a/iptables/iptables.c b/iptables/iptables.c index d246198f..6f7b3476 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -773,7 +773,6 @@ int do_command4(int argc, char *argv[], char **table, xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { e = generate_entry(&cs.fw, cs.matches, cs.target->t); - free(cs.target->t); } } @@ -875,7 +874,7 @@ int do_command4(int argc, char *argv[], char **table, if (verbose > 1) dump_entries(*handle); - xtables_rule_matches_free(&cs.matches); + xtables_clear_iptables_command_state(&cs); if (e != NULL) { free(e); -- cgit v1.2.3 From 16e1ce4ed32ac86eb834531282ae14fdb4e102ac Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 25 Nov 2022 21:47:52 +0100 Subject: xshared: Free data after printing help This is merely to make valgrind happy, but less noise means less real issues missed. Signed-off-by: Phil Sutter --- iptables/xshared.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iptables/xshared.c b/iptables/xshared.c index 2a894c19..f93529b1 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1543,6 +1543,9 @@ void do_parse(int argc, char *argv[], XTF_TRY_LOAD, &cs->matches); xtables_printhelp(cs->matches); + xtables_clear_iptables_command_state(cs); + xtables_free_opts(1); + xtables_fini(); exit(0); /* -- cgit v1.2.3 From 39a2aa8cbfc99f4a75dfc0786a80ced90952ab29 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Nov 2022 20:03:30 +0100 Subject: libiptc: Eliminate garbage access When adding a rule, valgrind prints: Syscall param socketcall.setsockopt(optval) points to uninitialised byte(s) at 0x4A8165A: setsockopt (in /lib64/libc.so.6) by 0x4857A48: iptc_commit (libiptc.c:2676) by 0x10E4BB: iptables_main (iptables-standalone.c:61) by 0x49A3349: (below main) (in /lib64/libc.so.6) Address 0x4b63788 is 40 bytes inside a block of size 1,448 alloc'd at 0x484659F: calloc (vg_replace_malloc.c:1328) by 0x4857654: iptc_commit (libiptc.c:2564) by 0x10E4BB: iptables_main (iptables-standalone.c:61) by 0x49A3349: (below main) (in /lib64/libc.so.6) This is because repl->counters is not initialized upon allocation. Since the field is an array, make use of calloc() which implicitly does the initialization. Fixes: e37c0dc100c51 ("Revert the recent addition of memset()'s to TC_COMMIT. One of them is bogus and the other one needs more investigation to why valgrind is complaining.") Signed-off-by: Phil Sutter --- libiptc/libiptc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 97823f93..f9b7779e 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -2554,8 +2554,8 @@ TC_COMMIT(struct xtc_handle *handle) + sizeof(STRUCT_COUNTERS) * new_number; /* These are the old counters we will get from kernel */ - repl->counters = malloc(sizeof(STRUCT_COUNTERS) - * handle->info.num_entries); + repl->counters = calloc(handle->info.num_entries, + sizeof(STRUCT_COUNTERS)); if (!repl->counters) { errno = ENOMEM; goto out_free_repl; -- cgit v1.2.3 From d1fb4f93d35860624c8a07844942febb113f2b65 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 13:06:25 +0100 Subject: ebtables: Implement --check command Sadly, '-C' is in use already for --change-counters (even though ebtables-nft does not implement this), so add a long-option only. It is needed for xlate testsuite in replay mode, which will use '--check' instead of '-C'. Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index c5fc3385..7214a767 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -198,6 +198,7 @@ struct option ebt_original_options[] = { "delete-chain" , optional_argument, 0, 'X' }, { "init-table" , no_argument , 0, 11 }, { "concurrent" , no_argument , 0, 13 }, + { "check" , required_argument, 0, 14 }, { 0 } }; @@ -730,6 +731,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, case 'N': /* Make a user defined chain */ case 'E': /* Rename chain */ case 'X': /* Delete chain */ + case 14: /* check a rule */ /* We allow -N chainname -P policy */ if (command == 'N' && c == 'P') { command = c; @@ -907,7 +909,8 @@ print_zero: if (!OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "No command specified"); - if (command != 'A' && command != 'D' && command != 'I' && command != 'C') + if (command != 'A' && command != 'D' && + command != 'I' && command != 'C' && command != 14) xtables_error(PARAMETER_PROBLEM, "Command and option do not match"); if (c == 'i') { @@ -1088,7 +1091,7 @@ print_zero: argv[optind]); if (command != 'A' && command != 'I' && - command != 'D' && command != 'C') + command != 'D' && command != 'C' && command != 14) xtables_error(PARAMETER_PROBLEM, "Extensions only for -A, -I, -D and -C"); } @@ -1109,7 +1112,7 @@ print_zero: /* Do the final checks */ if (command == 'A' || command == 'I' || - command == 'D' || command == 'C') { + command == 'D' || command == 'C' || command == 14) { for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next) xtables_option_mfcall(xtrm_i->match); @@ -1161,6 +1164,9 @@ print_zero: } else if (command == 'D') { ret = delete_entry(h, chain, *table, &cs, rule_nr - 1, rule_nr_end, flags & OPT_VERBOSE); + } else if (command == 14) { + ret = nft_cmd_rule_check(h, chain, *table, + &cs, flags & OPT_VERBOSE); } /*else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); if (ebt_errormsg[0] != '\0') -- cgit v1.2.3 From 7705b2daa3bdc1143e58a4e38224a3392ff3501a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 01:38:26 +0100 Subject: tests: xlate: Use --check to verify replay After applying the translated rule using nft, pass the untranslated rule to --check instead of dumping the ruleset and performing a string search. This fixes for mandatory match reordering (e.g. addresses before interfaces) and minor differences like /32 netmasks or even just whitespace changes. Fixes: 223e34b057b95 ("tests: xlate-test: Replay results for reverse direction testing") Signed-off-by: Phil Sutter --- xlate-test.py | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 6513b314..4f037ef6 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -67,6 +67,7 @@ def test_one_replay(name, sourceline, expected, result): srcwords = sourceline.split() srccmd = srcwords[0] + ipt = srccmd.split('-')[0] table_idx = -1 chain_idx = -1 table_name = "filter" @@ -84,16 +85,12 @@ def test_one_replay(name, sourceline, expected, result): if searchline is None: # adjust sourceline as required - srcwords[chain_idx] = "-A" - if table_idx >= 0: - srcwords.pop(table_idx) - srcwords.pop(table_idx) - searchline = " ".join(srcwords[1:]) - elif not searchline.startswith("-A"): - tmp = ["-A", chain_name] - if len(searchline) > 0: - tmp.extend(searchline) - searchline = " ".join(tmp) + checkcmd = srcwords[:] + checkcmd[0] = ipt + checkcmd[chain_idx] = "--check" + else: + checkcmd = [ipt, "-t", table_name] + checkcmd += ["--check", chain_name, searchline] fam = "" if srccmd.startswith("ip6"): @@ -110,30 +107,23 @@ def test_one_replay(name, sourceline, expected, result): rc, output, error = run_proc([args.nft, "-f", "-"], shell = False, input = "\n".join(nft_input)) if rc != 0: - result.append(name + ": " + red("Fail")) + result.append(name + ": " + red("Replay Fail")) result.append(args.nft + " call failed: " + error.rstrip('\n')) for line in nft_input: result.append(magenta("input: ") + line) return False - ipt = srccmd.split('-')[0] - rc, output, error = run_proc([xtables_nft_multi, ipt + "-save"]) + rc, output, error = run_proc([xtables_nft_multi] + checkcmd) if rc != 0: - result.append(name + ": " + red("Fail")) - result.append(ipt + "-save call failed: " + error) - return False - - if output.find(searchline) < 0: - outline = None - for l in output.split('\n'): - if l.startswith('-A '): - output = l - break - result.append(name + ": " + red("Replay fail")) - result.append(magenta("src: '") + str(expected) + "'") - result.append(magenta("exp: '") + searchline + "'") - for l in output.split('\n'): - result.append(magenta("res: ") + l) + result.append(name + ": " + red("Check Fail")) + result.append(magenta("check: ") + " ".join(checkcmd)) + result.append(magenta("error: ") + error) + rc, output, error = run_proc([xtables_nft_multi, ipt + "-save"]) + for l in output.split("\n"): + result.append(magenta("ipt: ") + l) + rc, output, error = run_proc([args.nft, "list", "ruleset"]) + for l in output.split("\n"): + result.append(magenta("nft: ") + l) return False return True -- cgit v1.2.3 From f200aca7ff7b6a0edbe9024f0543b3f58111c50e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 13:09:48 +0100 Subject: nft: Fix for comparing ifname matches against nft-generated ones Since nft adds the interface name as fixed-size string of 16 bytes, filling a mask based on the length value will not match the mask nft set. Fixes: 652b98e793711 ("xtables-compat: fix wildcard detection") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index f1503b6c..03e13fdc 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -279,7 +279,7 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned memcpy(dst, name, len); if (name[len - 1] == '\0') { if (mask) - memset(mask, 0xff, len); + memset(mask, 0xff, strlen(name) + 1); return; } -- cgit v1.2.3 From 5baa4279264bb4ab93c6e80b4887f2bd29691446 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 15:08:01 +0100 Subject: nft: Fix match generator for '! -i +' It's actually nonsense since it will never match, but iptables accepts it and the resulting nftables rule must behave identically. Reuse the solution implemented into xtables-translate (by commit e179e87a1179e) and turn the above match into 'iifname INVAL/D'. The commit this fixes merely ignored the fact that "any interface" match might be inverted. Fixes: 0a8635183edd0 ("xtables-compat: ignore '+' interface name") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 03e13fdc..2bb46709 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -168,6 +168,9 @@ void add_iniface(struct nft_handle *h, struct nftnl_rule *r, if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1, reg); + else if (op != NFT_CMP_EQ) + add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", + strlen("INVAL/D") + 1, reg); } else { add_cmp_ptr(r, op, iface, iface_len + 1, reg); } @@ -185,6 +188,9 @@ void add_outiface(struct nft_handle *h, struct nftnl_rule *r, if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1, reg); + else if (op != NFT_CMP_EQ) + add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", + strlen("INVAL/D") + 1, reg); } else { add_cmp_ptr(r, op, iface, iface_len + 1, reg); } -- cgit v1.2.3 From 29387a190f5ba04fb8a902dce9602292979a9ba2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 22 Oct 2022 15:26:56 +0200 Subject: nft: Recognize INVAL/D interface name It is just a hack to translate '! -i +' into a never matching nft rule, but recognize it anyway for completeness' sake and to make xlate replay test pass. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 2bb46709..56acbd45 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -359,6 +359,21 @@ static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) return 0; } +static void parse_invalid_iface(char *iface, unsigned char *mask, + uint8_t *invflags, uint8_t invbit) +{ + if (*invflags & invbit || strcmp(iface, "INVAL/D")) + return; + + /* nft's poor "! -o +" excuse */ + *invflags |= invbit; + iface[0] = '+'; + iface[1] = '\0'; + mask[0] = 0xff; + mask[1] = 0xff; + memset(mask + 2, 0, IFNAMSIZ - 2); +} + int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags) @@ -393,6 +408,8 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, *invflags |= IPT_INV_VIA_IN; parse_ifname(ifname, len, iniface, iniface_mask); + parse_invalid_iface(iniface, iniface_mask, + invflags, IPT_INV_VIA_IN); break; case NFT_META_BRI_OIFNAME: case NFT_META_OIFNAME: @@ -401,6 +418,8 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, *invflags |= IPT_INV_VIA_OUT; parse_ifname(ifname, len, outiface, outiface_mask); + parse_invalid_iface(outiface, outiface_mask, + invflags, IPT_INV_VIA_OUT); break; case NFT_META_MARK: parse_meta_mark(ctx, e); -- cgit v1.2.3 From ba1c0fe89eb56f8bf25f9165f2e5dc366ea0118c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 15:16:43 +0100 Subject: xtables-translate: Fix for interfaces with asterisk mid-string For nft, asterisk is special at end of the interface name only. Escaping it mid-string makes the escape char part of the interface name, so avoid this. In the test case, also drop the ticks around interface names in *-translate command - since there's no shell involved which would eat them, they become part of the interface name. Fixes: e179e87a1179e ("xtables-translate: Fix for interface name corner-cases") Signed-off-by: Phil Sutter --- extensions/generic.txlate | 14 +++++++------- iptables/xtables-translate.c | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/extensions/generic.txlate b/extensions/generic.txlate index 7e879fd5..d7ddf6a3 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -74,17 +74,17 @@ ebtables-translate -I INPUT -p ! Length nft 'insert rule bridge filter INPUT ether type >= 0x0600 counter' # asterisk is not special in iptables and it is even a valid interface name -iptables-translate -A FORWARD -i '*' -o 'eth*foo' -nft 'add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter' +iptables-translate -A FORWARD -i * -o eth*foo +nft 'add rule ip filter FORWARD iifname "\*" oifname "eth*foo" counter' -# escape all asterisks but translate only the first plus character -iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++' -nft 'add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter' +# escape only suffix asterisk and translate only the last plus character +iptables-translate -A FORWARD -i eth*foo*+ -o eth++ +nft 'add rule ip filter FORWARD iifname "eth*foo**" oifname "eth+*" counter' # skip for always matching interface names -iptables-translate -A FORWARD -i '+' +iptables-translate -A FORWARD -i + nft 'add rule ip filter FORWARD counter' # match against invalid interface name to simulate never matching rule -iptables-translate -A FORWARD ! -i '+' +iptables-translate -A FORWARD ! -i + nft 'add rule ip filter FORWARD iifname "INVAL/D" counter' diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 102973a6..22b2fbc8 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -41,7 +41,9 @@ void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname, for (i = 0, j = 0; i < ifaclen + 1; i++, j++) { switch (ifname[i]) { case '*': - iface[j++] = '\\'; + /* asterisk is non-special mid-string */ + if (i == ifaclen - 1) + iface[j++] = '\\'; /* fall through */ default: iface[j] = ifname[i]; -- cgit v1.2.3 From 39589b3edb7c0ea3e64777c7f4cdbf45be55ce53 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 1 Dec 2022 13:03:49 +0100 Subject: ebtables: Fix MAC address match translation If a mask was present, ebtables-translate would emit illegal syntax. Fixes: 5e2b473a64bc7 ("xtables-compat: extend generic tests for masks and wildcards") Signed-off-by: Phil Sutter --- extensions/generic.txlate | 2 +- iptables/nft-bridge.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/generic.txlate b/extensions/generic.txlate index d7ddf6a3..c24ed156 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -65,7 +65,7 @@ ebtables-translate -A FORWARD ! -i iname --logical-in ilogname -o out+ --logical nft 'add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter' ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00 -nft 'insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter' +nft 'insert rule bridge filter INPUT ether type 0x800 ether daddr and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter' ebtables-translate -I INPUT -p Length nft 'insert rule bridge filter INPUT ether type < 0x0600 counter' diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 8d002c17..e223d197 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -866,17 +866,17 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : ""); - xlate_mac(xl, mac); - if (memcmp(mask, one_msk, ETH_ALEN)) { int i; - xt_xlate_add(xl, " and "); + xt_xlate_add(xl, "and"); xlate_mac(xl, mask); xt_xlate_add(xl, " == %02x", mac[0] & mask[0]); for (i=1; i < ETH_ALEN; i++) xt_xlate_add(xl, ":%02x", mac[i] & mask[i]); + } else { + xlate_mac(xl, mac); } } -- cgit v1.2.3 From bf8bc21b5d0fb386bb14019ebe7ebab6dd85cdef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 8 Dec 2022 01:29:48 +0100 Subject: Makefile: Create LZMA-compressed dist-files Use a more modern alternative to bzip2. Suggested-by: Jan Engelhardt Suggested-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 799bf8b8..19a93a55 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 -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.xz --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/; rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; config.status: extensions/GNUmakefile.in \ -- cgit v1.2.3 From 92ce78d04677d4d1b6d0144bed6e50180adc7d82 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 3 Dec 2022 22:44:40 +0100 Subject: Drop INCOMPATIBILITIES file The problems described in there were relevant 17 years ago. Signed-off-by: Phil Sutter --- INCOMPATIBILITIES | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 INCOMPATIBILITIES diff --git a/INCOMPATIBILITIES b/INCOMPATIBILITIES deleted file mode 100644 index ddb24087..00000000 --- a/INCOMPATIBILITIES +++ /dev/null @@ -1,14 +0,0 @@ -INCOMPATIBILITIES: - -- The REJECT target has an '--reject-with admin-prohib' option which used - with kernels that do not support it, will result in a plain DROP instead - of REJECT. Use with caution. - Kernels that do support it: - 2.4 - since 2.4.22-pre9 - 2.6 - all - -- There are some issues related to upgrading from 1.2.x to 1.3.x on a system - with dynamic ruleset changes during runtime. (Please see - https://bugzilla.netfilter.org/bugzilla/show_bug.cgi?id=334). - After upgrading from 1.2 to 1.3, it suggest go do an iptables-save, then - iptables-restore to ensure your dynamic rule changes continue to work. -- cgit v1.2.3 From 53153775b08f830b940d04efbc7b38bc40aaa4b3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 3 Dec 2022 22:45:59 +0100 Subject: Drop libiptc/linux_stddef.h This header was never included anywhere. Fixes: aae69bed01982 ("complete libiptc rewrite. Time to load 10k rules goes down from 2.20 minutes to 1.255 seconds (!). Might still contain bugs, use with caution.") Signed-off-by: Phil Sutter --- libiptc/linux_stddef.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 libiptc/linux_stddef.h diff --git a/libiptc/linux_stddef.h b/libiptc/linux_stddef.h deleted file mode 100644 index 56416f10..00000000 --- a/libiptc/linux_stddef.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _LINUX_STDDEF_H -#define _LINUX_STDDEF_H - -#undef NULL -#if defined(__cplusplus) -#define NULL 0 -#else -#define NULL ((void *)0) -#endif - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - - -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Check at compile time that something is of a particular type. - * Always evaluates to 1 so you may use it easily in comparisons. - */ -#define typecheck(type,x) \ -({ type __dummy; \ - typeof(x) __dummy2; \ - (void)(&__dummy == &__dummy2); \ - 1; \ -}) - - -#endif -- cgit v1.2.3 From 127eadee563e4e7b741dc532e0b70b7dabf5481c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 3 Dec 2022 23:20:58 +0100 Subject: Makefile: Generate ip6tables man pages on the fly No need to drag them around, creating them is simple. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 3 +++ iptables/ip6tables-apply.8 | 1 - iptables/ip6tables-restore.8 | 1 - iptables/ip6tables-save.8 | 1 - iptables/ip6tables.8 | 1 - 5 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 iptables/ip6tables-apply.8 delete mode 100644 iptables/ip6tables-restore.8 delete mode 100644 iptables/ip6tables-save.8 delete mode 100644 iptables/ip6tables.8 diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 23f8352d..8c346698 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -105,6 +105,9 @@ iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../e iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8: ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@ +ip6tables.8 ip6tables-apply.8 ip6tables-restore.8 ip6tables-save.8: + ${AM_VERBOSE_GEN} echo "$@" | sed 's|^ip6|.so man8/ip|' >$@ + pkgconfig_DATA = xtables.pc # Using if..fi avoids an ugly "error (ignored)" message :) diff --git a/iptables/ip6tables-apply.8 b/iptables/ip6tables-apply.8 deleted file mode 100644 index 994b487a..00000000 --- a/iptables/ip6tables-apply.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-apply.8 diff --git a/iptables/ip6tables-restore.8 b/iptables/ip6tables-restore.8 deleted file mode 100644 index cf4ea3e7..00000000 --- a/iptables/ip6tables-restore.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-restore.8 diff --git a/iptables/ip6tables-save.8 b/iptables/ip6tables-save.8 deleted file mode 100644 index 182f55c1..00000000 --- a/iptables/ip6tables-save.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-save.8 diff --git a/iptables/ip6tables.8 b/iptables/ip6tables.8 deleted file mode 100644 index 0dee41ad..00000000 --- a/iptables/ip6tables.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables.8 -- cgit v1.2.3 From b0f8aae7c7deb8264c3b4f626fe1ecf98edc5eb9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 5 Dec 2022 14:25:43 +0100 Subject: extensions: Makefile: Merge initext targets Abstract initext*.c and .initext*.dd stamp file recipes so a single one serves for all variants. Signed-off-by: Phil Sutter --- extensions/GNUmakefile.in | 106 ++++++---------------------------------------- 1 file changed, 14 insertions(+), 92 deletions(-) diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 0239a06a..188e7a79 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -175,111 +175,33 @@ initexta_func := $(addprefix arpt_,${pfa_build_mod}) initext4_func := $(addprefix ipt_,${pf4_build_mod}) initext6_func := $(addprefix ip6t_,${pf6_build_mod}) -.initext.dd: FORCE - @echo "${initext_func}" >$@.tmp; \ - cmp -s $@ $@.tmp || mv $@.tmp $@; \ - rm -f $@.tmp; - -.initextb.dd: FORCE - @echo "${initextb_func}" >$@.tmp; \ - cmp -s $@ $@.tmp || mv $@.tmp $@; \ - rm -f $@.tmp; - -.initexta.dd: FORCE - @echo "${initexta_func}" >$@.tmp; \ - cmp -s $@ $@.tmp || mv $@.tmp $@; \ - rm -f $@.tmp; - -.initext4.dd: FORCE - @echo "${initext4_func}" >$@.tmp; \ - cmp -s $@ $@.tmp || mv $@.tmp $@; \ - rm -f $@.tmp; +initexts := ext exta extb ext4 ext6 +initext_depfiles = $(patsubst %,.init%.dd,${initexts}) +initext_sources = $(patsubst %,init%.c,${initexts}) -.initext6.dd: FORCE - @echo "${initext6_func}" >$@.tmp; \ +${initext_depfiles}: FORCE + @echo "$(value $(patsubst .%.dd,%,$@)_func)" >$@.tmp; \ cmp -s $@ $@.tmp || mv $@.tmp $@; \ rm -f $@.tmp; -initext.c: .initext.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions(void);" >>$@; \ - echo "void init_extensions(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - -initextb.c: .initextb.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initextb_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensionsb(void);" >>$@; \ - echo "void init_extensionsb(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initextb_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - -initexta.c: .initexta.dd +${initext_sources}: %.c: .%.dd ${AM_VERBOSE_GEN} @( \ + initext_func="$(value $(basename $@)_func)"; \ + funcname="init_extensions$(patsubst initext%.c,%,$@)"; \ echo "" >$@; \ - for i in ${initexta_func}; do \ + for i in $${initext_func}; do \ echo "extern void lib$${i}_init(void);" >>$@; \ done; \ - echo "void init_extensionsa(void);" >>$@; \ - echo "void init_extensionsa(void)" >>$@; \ + echo "void $${funcname}(void);" >>$@; \ + echo "void $${funcname}(void)" >>$@; \ echo "{" >>$@; \ - for i in ${initexta_func}; do \ + for i in $${initext_func}; do \ echo " ""lib$${i}_init();" >>$@; \ done; \ echo "}" >>$@; \ ); -initext4.c: .initext4.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext4_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions4(void);" >>$@; \ - echo "void init_extensions4(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext4_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - -initext6.c: .initext6.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext6_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions6(void);" >>$@; \ - echo "void init_extensions6(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext6_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - # # Manual pages # @@ -308,8 +230,8 @@ man_run = \ fi; \ done >$@; -matches.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) +matches.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man) $(call man_run,$(call ex_matches,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) -targets.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) +targets.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man) $(call man_run,$(call ex_targets,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) -- cgit v1.2.3 From a8c50458cf5572c3ec3841bdeb0ec01058df476c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 5 Dec 2022 17:29:30 +0100 Subject: iptables/Makefile: Reorg variable assignments Introduce helper variables holding SOURCES, LDADD and CFLAGS used by both legacy and nft builds. Specify also internal header files, builds should depend on them. Doing that, reorder lists for clarity. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 58 +++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 8c346698..77202ad8 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -6,46 +6,52 @@ AM_LDFLAGS = ${regular_LDFLAGS} BUILT_SOURCES = -xtables_legacy_multi_SOURCES = xtables-legacy-multi.c iptables-xml.c -xtables_legacy_multi_CFLAGS = ${AM_CFLAGS} -xtables_legacy_multi_LDADD = ../extensions/libext.a +common_sources = iptables-xml.c xtables-multi.h xshared.c xshared.h +common_ldadd = ../extensions/libext.a ../libxtables/libxtables.la -lm +common_cflags = ${AM_CFLAGS} if ENABLE_STATIC -xtables_legacy_multi_CFLAGS += -DALL_INCLUSIVE +common_cflags += -DALL_INCLUSIVE endif + +xtables_legacy_multi_SOURCES = ${common_sources} xtables-legacy-multi.c \ + iptables-restore.c iptables-save.c +xtables_legacy_multi_CFLAGS = ${common_cflags} +xtables_legacy_multi_LDADD = ${common_ldadd} if ENABLE_IPV4 -xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c +xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c iptables-multi.h 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-standalone.c ip6tables.c +xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c ip6tables-multi.h xtables_legacy_multi_CFLAGS += -DENABLE_IPV6 xtables_legacy_multi_LDADD += ../libiptc/libip6tc.la ../extensions/libext6.a endif -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 if ENABLE_NFTABLES -xtables_nft_multi_SOURCES = xtables-nft-multi.c iptables-xml.c -xtables_nft_multi_CFLAGS = ${AM_CFLAGS} -xtables_nft_multi_LDADD = ../extensions/libext.a ../extensions/libext_ebt.a -if ENABLE_STATIC -xtables_nft_multi_CFLAGS += -DALL_INCLUSIVE -endif +xtables_nft_multi_SOURCES = ${common_sources} xtables-nft-multi.c +xtables_nft_multi_CFLAGS = ${common_cflags} +xtables_nft_multi_LDADD = ${common_ldadd} \ + ../extensions/libext_arpt.a \ + ../extensions/libext_ebt.a \ + ../extensions/libext4.a \ + ../extensions/libext6.a \ + ${libmnl_LIBS} ${libnftnl_LIBS} \ + ${libnetfilter_conntrack_LIBS} xtables_nft_multi_CFLAGS += -DENABLE_NFTABLES -DENABLE_IPV4 -DENABLE_IPV6 -xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \ - xtables-standalone.c xtables.c nft.c \ - nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \ - xtables-monitor.c nft-cache.c \ - xtables-arp.c \ - nft-bridge.c nft-cmd.c nft-chain.c \ - xtables-eb-standalone.c xtables-eb.c \ - xtables-eb-translate.c \ - xtables-translate.c -xtables_nft_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a -xtables_nft_multi_SOURCES += xshared.c -xtables_nft_multi_LDADD += ../libxtables/libxtables.la -lm +xtables_nft_multi_SOURCES += nft.c nft.h \ + nft-arp.c nft-ipv4.c nft-ipv6.c \ + nft-bridge.c nft-bridge.h \ + nft-cache.c nft-cache.h \ + nft-chain.c nft-chain.h \ + nft-cmd.c nft-cmd.h \ + nft-shared.c nft-shared.h \ + xtables-monitor.c \ + xtables.c xtables-arp.c xtables-eb.c \ + xtables-standalone.c xtables-eb-standalone.c \ + xtables-translate.c xtables-eb-translate.c \ + xtables-save.c xtables-restore.c endif sbin_PROGRAMS = xtables-legacy-multi -- cgit v1.2.3 From e10f1a2a2d8756c9e9924c9328d507daab14a0ef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 5 Dec 2022 18:56:09 +0100 Subject: iptables/Makefile: Split nft-variant man page list Some of them are not generated and must therefore be distributed. Hence add them to a 'dist_man_MANS' variable. This leaves only generated entries in the non-dist one, so use that to reduce the CLEANFILES list. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 77202ad8..7ca2b1a4 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -66,19 +66,15 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ sbin_SCRIPTS = iptables-apply if ENABLE_NFTABLES -man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ - iptables-translate.8 ip6tables-translate.8 \ +man_MANS += iptables-translate.8 ip6tables-translate.8 \ iptables-restore-translate.8 ip6tables-restore-translate.8 \ - xtables-monitor.8 \ - arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ - ebtables-nft.8 + xtables-monitor.8 + +dist_man_MANS = xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ + arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ + ebtables-nft.8 endif -CLEANFILES = iptables.8 xtables-monitor.8 \ - iptables-xml.1 iptables-apply.8 \ - iptables-extensions.8 iptables-extensions.8.tmpl \ - iptables-restore.8 iptables-save.8 \ - iptables-restore-translate.8 ip6tables-restore-translate.8 \ - iptables-translate.8 ip6tables-translate.8 +CLEANFILES = ${man_MANS} iptables-extensions.8.tmpl vx_bin_links = iptables-xml if ENABLE_IPV4 -- cgit v1.2.3 From 3822a992bc2772d55853fb768225210af5d35e02 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 6 Dec 2022 20:35:42 +0100 Subject: Makefile: Fix for 'make distcheck' Since extensions/ directory does not use automake, some targets have to be added manually. Apart from that, several Makefiles either missed to specify relevant files or did not specify them correctly for 'make dist' to add them to the tarball. Signed-off-by: Phil Sutter --- Makefile.am | 4 +++- extensions/GNUmakefile.in | 15 ++++++++++++++- include/Makefile.am | 2 ++ iptables/Makefile.am | 5 ++++- libipq/Makefile.am | 2 +- libiptc/Makefile.am | 2 ++ utils/Makefile.am | 4 ++-- 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 19a93a55..a0bf11e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,9 +16,11 @@ SUBDIRS += extensions # Depends on extensions/libext.a: SUBDIRS += iptables +EXTRA_DIST = autogen.sh iptables-test.py xlate-test.py + if ENABLE_NFTABLES confdir = $(sysconfdir) -dist_conf_DATA = etc/ethertypes +dist_conf_DATA = etc/ethertypes etc/xtables.conf endif .PHONY: tarball diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 188e7a79..c37e4619 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -79,7 +79,7 @@ targets_install := .SECONDARY: -.PHONY: all install uninstall clean distclean FORCE +.PHONY: all install uninstall clean distclean FORCE dvi check installcheck all: ${targets} @@ -235,3 +235,16 @@ matches.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man) targets.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man) $(call man_run,$(call ex_targets,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) + +dist_initext_src = $(addprefix $(srcdir)/,${initext_sources}) +dist_sources = $(filter-out ${dist_initext_src},$(wildcard $(srcdir)/*.[ch])) + +distdir: + mkdir -p $(distdir) + cp -p ${dist_sources} $(distdir)/ + cp -p $(wildcard ${srcdir}/lib*.man) $(distdir)/ + cp -p $(srcdir)/*.{t,txlate} $(distdir)/ + +dvi: +check: all +installcheck: diff --git a/include/Makefile.am b/include/Makefile.am index ea34c2fe..348488a4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -11,6 +11,8 @@ nobase_include_HEADERS += \ libiptc/ipt_kernel_headers.h libiptc/libiptc.h \ libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h +EXTRA_DIST = iptables linux iptables.h ip6tables.h + uninstall-hook: dir=${includedir}/libiptc; { \ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 7ca2b1a4..4353dd00 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -63,7 +63,8 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ ip6tables-save.8 iptables-extensions.8 \ iptables-apply.8 ip6tables-apply.8 -sbin_SCRIPTS = iptables-apply +dist_sbin_SCRIPTS = iptables-apply +dist_pkgdata_DATA = iptables.xslt if ENABLE_NFTABLES man_MANS += iptables-translate.8 ip6tables-translate.8 \ @@ -144,3 +145,5 @@ uninstall-hook: ); \ ( cd "$$dir" && rm -f ip6tables-apply ); \ } + +EXTRA_DIST = tests diff --git a/libipq/Makefile.am b/libipq/Makefile.am index 2cdaf32e..68da15fe 100644 --- a/libipq/Makefile.am +++ b/libipq/Makefile.am @@ -6,7 +6,7 @@ AM_LDFLAGS = ${regular_LDFLAGS} libipq_la_SOURCES = libipq.c lib_LTLIBRARIES = libipq.la -man_MANS = ipq_create_handle.3 ipq_destroy_handle.3 ipq_errstr.3 \ +dist_man_MANS = ipq_create_handle.3 ipq_destroy_handle.3 ipq_errstr.3 \ ipq_get_msgerr.3 ipq_get_packet.3 ipq_message_type.3 \ ipq_perror.3 ipq_read.3 ipq_set_mode.3 ipq_set_verdict.3 \ libipq.3 diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am index 097842f2..d8fe169e 100644 --- a/libiptc/Makefile.am +++ b/libiptc/Makefile.am @@ -11,3 +11,5 @@ libip4tc_la_SOURCES = libip4tc.c libip4tc_la_LDFLAGS = -version-info 2:0:0 libip6tc_la_SOURCES = libip6tc.c libip6tc_la_LDFLAGS = -version-info 2:0:0 + +EXTRA_DIST = libiptc.c linux_list.h diff --git a/utils/Makefile.am b/utils/Makefile.am index 327a29e0..e9eec48f 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -6,13 +6,13 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \ AM_LDFLAGS = ${regular_LDFLAGS} sbin_PROGRAMS = -pkgdata_DATA = +dist_pkgdata_DATA = man_MANS = if HAVE_LIBNFNETLINK man_MANS += nfnl_osf.8 sbin_PROGRAMS += nfnl_osf -pkgdata_DATA += pf.os +dist_pkgdata_DATA += pf.os nfnl_osf_LDADD = ${libnfnetlink_LIBS} -- cgit v1.2.3 From 9fbca4e045a837a77798ef57336436daf3940b41 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 6 Dec 2022 21:05:04 +0100 Subject: Makefile: Generate .tar.xz archive with 'make dist' Instead of the default .tar.gz one. Signed-off-by: Phil Sutter --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index a0bf11e6..61604d32 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # -*- Makefile -*- ACLOCAL_AMFLAGS = -I m4 -AUTOMAKE_OPTIONS = foreign subdir-objects +AUTOMAKE_OPTIONS = foreign subdir-objects dist-xz no-dist-gzip SUBDIRS = libiptc libxtables if ENABLE_DEVEL -- cgit v1.2.3 From 19f03b7a2a21f22a53b6b0d2f542062986e2f807 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 7 Dec 2022 17:23:12 +0100 Subject: include/Makefile: xtables-version.h is generated List it in nodist_include_HEADERS so it is installed but not distributed - configure generates it from xtables-version.h.in. While being at it, list xtables.h in plain include_HEADERS. It doesn't sit in a sub-dir, so the nobase prefix does not make a difference. Fixes: df60a301bf24c ("build: separate AC variable replacements from xtables.h") Signed-off-by: Phil Sutter --- include/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/Makefile.am b/include/Makefile.am index 348488a4..07c88b90 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,13 +1,13 @@ # -*- Makefile -*- -include_HEADERS = -nobase_include_HEADERS = xtables.h xtables-version.h +include_HEADERS = xtables.h +nodist_include_HEADERS = xtables-version.h if ENABLE_LIBIPQ include_HEADERS += libipq/libipq.h endif -nobase_include_HEADERS += \ +nobase_include_HEADERS = \ libiptc/ipt_kernel_headers.h libiptc/libiptc.h \ libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h -- cgit v1.2.3 From c32410edee6a855a1557359caecc5f0b98d8cbe1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 15 Oct 2022 11:43:01 +0200 Subject: tests: Adjust testsuite return codes to automake guidelines As per the manual[1]: "When no test protocol is in use, an exit status of 0 from a test script will denote a success, an exit status of 77 a skipped test, an exit status of 99 a hard error, and any other exit status will denote a failure." [1] https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html Signed-off-by: Phil Sutter --- iptables-test.py | 2 +- iptables/tests/shell/run-tests.sh | 4 +++- xlate-test.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index dc031c2b..de1e1e95 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -579,7 +579,7 @@ def main(): if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) - return + return 77 if not args.netns and not args.no_netns and not spawn_netns(): print("Cannot run in own namespace, connectivity might break", diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index 7a80af34..11256905 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -21,7 +21,6 @@ EOF msg_error() { echo "E: $1 ..." >&2 - exit 1 } msg_warn() { @@ -34,10 +33,12 @@ msg_info() { if [ "$(id -u)" != "0" ] ; then msg_error "this requires root!" + exit 77 fi if [ ! -d "$TESTDIR" ] ; then msg_error "missing testdir $TESTDIR" + exit 99 fi # support matching repeated pattern in SINGLE check below @@ -76,6 +77,7 @@ while [ -n "$1" ]; do ;; *) msg_error "unknown parameter '$1'" + exit 99 ;; esac done diff --git a/xlate-test.py b/xlate-test.py index 4f037ef6..4cb1401b 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -250,7 +250,7 @@ def main(): tests, passed, failed, errors = run_test(args.test, payload) except IOError: print(red("Error: ") + "test file does not exist", file=sys.stderr) - return -1 + return 99 else: files, tests, passed, failed, errors = load_test_files() -- cgit v1.2.3 From e1eaa04e31e44eab729e4a39a9967c6f1e24d499 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 15 Oct 2022 12:25:28 +0200 Subject: Makefile.am: Integrate testsuites Support calling 'make check' in topdir to run all three testsuites. While updating .gitignore, also add 'configure~' my autotools create and the tags file. Signed-off-by: Phil Sutter --- .gitignore | 12 ++++++++++++ Makefile.am | 2 ++ 2 files changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index a206fb48..ec4e44ca 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ Makefile.in /build-aux/ /config.* /configure +/configure~ /libtool /stamp-h1 /iptables/iptables-apply.8 @@ -29,3 +30,14 @@ Makefile.in # vim/nano swap file *.swp + +/tags + +# make check results +/test-suite.log +/iptables-test.py.log +/iptables-test.py.trs +/xlate-test.py.log +/xlate-test.py.trs +iptables/tests/shell/run-tests.sh.log +iptables/tests/shell/run-tests.sh.trs diff --git a/Makefile.am b/Makefile.am index 61604d32..451c3cb2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,3 +33,5 @@ tarball: config.status: extensions/GNUmakefile.in \ include/xtables-version.h.in + +TESTS = xlate-test.py iptables-test.py iptables/tests/shell/run-tests.sh -- cgit v1.2.3 From d96d0791901c10d4edf599b3da069ca3d9acfcc5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Dec 2022 13:20:21 +0100 Subject: nft: Parse icmp header matches These were previously ignored. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 74 ++++++++++++++++++++++ .../testcases/nft-only/0010-iptables-nft-save.txt | 6 +- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 56acbd45..d4b21921 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -833,6 +833,65 @@ static void nft_parse_tcp(struct nft_xt_ctx *ctx, op, dport, XT_TCP_INV_DSTPT); } +static void nft_parse_icmp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + struct nft_xt_ctx_reg *sreg, + uint8_t op, const char *data, size_t dlen) +{ + struct xtables_match *match; + struct ipt_icmp icmp = { + .type = UINT8_MAX, + .code = { 0, UINT8_MAX }, + }; + + if (dlen < 1) + goto out_err_len; + + switch (sreg->payload.offset) { + case 0: + icmp.type = data[0]; + if (dlen == 1) + break; + dlen--; + data++; + /* fall through */ + case 1: + if (dlen > 1) + goto out_err_len; + icmp.code[0] = icmp.code[1] = data[0]; + break; + default: + ctx->errmsg = "unexpected payload offset"; + return; + } + + switch (ctx->h->family) { + case NFPROTO_IPV4: + match = nft_create_match(ctx, cs, "icmp"); + break; + case NFPROTO_IPV6: + if (icmp.type == UINT8_MAX) { + ctx->errmsg = "icmp6 code with any type match not supported"; + return; + } + match = nft_create_match(ctx, cs, "icmp6"); + break; + default: + ctx->errmsg = "unexpected family for icmp match"; + return; + } + + if (!match) { + ctx->errmsg = "icmp match extension not found"; + return; + } + memcpy(match->m->data, &icmp, sizeof(icmp)); + return; + +out_err_len: + ctx->errmsg = "unexpected RHS data length"; +} + static void nft_parse_th_port(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, uint8_t proto, @@ -915,6 +974,21 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, return; } + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + nft_parse_icmp(ctx, cs, sreg, op, + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), + len); + return; + default: + ctx->errmsg = "unsupported layer 4 protocol value"; + return; + } + switch(sreg->payload.offset) { case 0: /* th->sport */ switch (len) { diff --git a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt index 73d7108c..5ee4c231 100644 --- a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt +++ b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt @@ -13,9 +13,9 @@ -A INPUT -d 0.0.0.0/2 -m ttl --ttl-gt 2 -j ACCEPT -A INPUT -d 0.0.0.0/3 -m ttl --ttl-lt 254 -j ACCEPT -A INPUT -d 0.0.0.0/4 -m ttl ! --ttl-eq 255 -j DROP --A INPUT -d 8.0.0.0/5 -p icmp -j ACCEPT --A INPUT -d 8.0.0.0/6 -p icmp -j ACCEPT --A INPUT -d 10.0.0.0/7 -p icmp -j ACCEPT +-A INPUT -d 8.0.0.0/5 -p icmp -m icmp --icmp-type 1 -j ACCEPT +-A INPUT -d 8.0.0.0/6 -p icmp -m icmp --icmp-type 2/3 -j ACCEPT +-A INPUT -d 10.0.0.0/7 -p icmp -m icmp --icmp-type 8 -j ACCEPT -A INPUT -m pkttype --pkt-type broadcast -j ACCEPT -A INPUT -m pkttype ! --pkt-type unicast -j DROP -A INPUT -p tcp -- cgit v1.2.3 From f2c5e52863ea48838e9b9246ed94419053673b88 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Dec 2022 16:06:11 +0100 Subject: arptables: Check the mandatory ar_pln match This match is added by nft_arp_add() to every rule with same value, so when parsing just check it is as expected and otherwise ignore it. This allows to treat matches on all other offsets/lengths as error. Fixes: 84909d171585d ("xtables: bootstrap ARP compatibility layer for nftables") Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index d670cbe6..edf17952 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -214,7 +214,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, struct arpt_entry *fw = &cs->arp; struct in_addr addr; uint16_t ar_hrd, ar_pro, ar_op; - uint8_t ar_hln; + uint8_t ar_hln, ar_pln; bool inv; switch (reg->payload.offset) { @@ -246,6 +246,11 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, if (inv) fw->arp.invflags |= IPT_INV_ARPOP; break; + case offsetof(struct arphdr, ar_pln): + get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); + if (ar_pln != 4 || inv) + ctx->errmsg = "unexpected ARP protocol length match"; + break; default: if (reg->payload.offset == sizeof(struct arphdr)) { if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) -- cgit v1.2.3 From 9075c3aa983d96c4331cb28fab5f30afd52bbb21 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Dec 2022 15:08:01 +0100 Subject: nft: Increase rule parser strictness Catch more unexpected conditions. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 2 ++ iptables/nft-bridge.c | 4 ++++ iptables/nft-ipv4.c | 4 +++- iptables/nft-ipv6.c | 4 +++- iptables/nft-shared.c | 35 +++++++++++++++++++++++++---------- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index edf17952..210f43d2 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -288,6 +288,8 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, if (inv) fw->arp.invflags |= IPT_INV_DSTIP; + } else { + ctx->errmsg = "unknown payload offset"; } break; } diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index e223d197..83cbe315 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -287,6 +287,10 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, fw->invflags |= EBT_IPROTO; fw->bitmask &= ~EBT_NOPROTO; break; + default: + DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; } } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 42167351..dcc4a8ed 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -207,10 +207,12 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, cs->fw.ip.invflags |= IPT_INV_FRAG; break; case offsetof(struct iphdr, ttl): - nft_parse_hl(ctx, e, cs); + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; break; default: DEBUGP("unknown payload offset %d\n", sreg->payload.offset); + ctx->errmsg = "unknown payload offset"; break; } } diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 3a373b7e..e9892185 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -173,10 +173,12 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, if (inv) cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; case offsetof(struct ip6_hdr, ip6_hlim): - nft_parse_hl(ctx, e, cs); + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; break; default: DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; break; } } diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index d4b21921..c13fc307 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -444,8 +444,10 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) size_t size; target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) + if (target == NULL) { + ctx->errmsg = "target extension not found"; return; + } size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; @@ -482,8 +484,10 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); - if (match == NULL) + if (match == NULL) { + ctx->errmsg = "match extension not found"; return; + } m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); memcpy(&m->data, mt_info, mt_len); @@ -690,9 +694,10 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, if (!tcp) { match = nft_create_match(ctx, cs, "tcp"); - if (!match) + if (!match) { + ctx->errmsg = "tcp match extension not found"; return NULL; - + } tcp = (void*)match->m->data; ctx->tcpudp.tcp = tcp; } @@ -904,6 +909,8 @@ static void nft_parse_th_port(struct nft_xt_ctx *ctx, case IPPROTO_TCP: nft_parse_tcp(ctx, cs, sport, dport, op); break; + default: + ctx->errmsg = "unknown layer 4 protocol for TH match"; } } @@ -957,8 +964,8 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, proto = ctx->cs->fw6.ipv6.proto; break; default: - proto = 0; - break; + ctx->errmsg = "invalid family for TH match"; + return; } nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); @@ -1129,8 +1136,10 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) if (!dreg) return; - if (len > sizeof(dreg->immediate.data)) + if (len > sizeof(dreg->immediate.data)) { + ctx->errmsg = "oversized immediate data"; return; + } memcpy(dreg->immediate.data, imm_data, len); dreg->immediate.len = len; @@ -1163,8 +1172,10 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - if (!cs->target) + if (!cs->target) { + ctx->errmsg = "verdict extension not found"; return; + } size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size; t = xtables_calloc(1, size); @@ -1197,8 +1208,10 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } match = xtables_find_match("limit", XTF_TRY_LOAD, matches); - if (match == NULL) + if (match == NULL) { + ctx->errmsg = "limit match extension not found"; return; + } size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; match->m = xtables_calloc(1, size); @@ -1245,8 +1258,10 @@ static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); target = xtables_find_target("NFLOG", XTF_TRY_LOAD); - if (target == NULL) + if (target == NULL) { + ctx->errmsg = "NFLOG target extension not found"; return; + } target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + XT_ALIGN(sizeof(struct xt_nflog_info_nft)); -- cgit v1.2.3 From ec86937089a95ac57f149b70cbf740d69b9bd775 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Dec 2022 16:17:35 +0100 Subject: nft: Make rule parsing errors fatal Finish parsing the rule, thereby printing all potential problems and abort the program. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index c13fc307..4a7b5406 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1362,7 +1362,7 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h, nft_parse_range(&ctx, expr); if (ctx.errmsg) { - fprintf(stderr, "%s", ctx.errmsg); + fprintf(stderr, "Error: %s\n", ctx.errmsg); ctx.errmsg = NULL; ret = false; } @@ -1404,6 +1404,8 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h, if (!cs->jumpto) cs->jumpto = ""; + if (!ret) + xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed"); return ret; } -- cgit v1.2.3 From 596f2e31ae7cee26e4f39f300cc69605f4ba512f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 22 Dec 2022 15:58:27 +0100 Subject: nft: Reject tcp/udp extension without proper protocol match Internally, 'th' expression is used, which works but matches both protocols. Since users won't expect '-m tcp --dport 1' to match UDP packets, catch missing/wrong '-p' argument. Fixes: c034cf31dd1a9 ("nft: prefer native expressions instead of udp match") Signed-off-by: Phil Sutter --- extensions/libxt_tcp.t | 3 +++ extensions/libxt_udp.t | 3 +++ iptables/nft.c | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t index b0e8006e..7a3bbd08 100644 --- a/extensions/libxt_tcp.t +++ b/extensions/libxt_tcp.t @@ -22,5 +22,8 @@ -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG RST;=;OK +-m tcp --dport 1;;FAIL +-m tcp --dport 1 -p tcp;-p tcp -m tcp --dport 1;OK +-m tcp --dport 1 -p 6;-p tcp -m tcp --dport 1;OK # should we accept this below? -p tcp -m tcp;=;OK diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t index 1b4d3dd6..f5347701 100644 --- a/extensions/libxt_udp.t +++ b/extensions/libxt_udp.t @@ -18,5 +18,8 @@ # -p udp -m udp --sport 65536;;FAIL -p udp -m udp --sport -1;;FAIL -p udp -m udp --dport -1;;FAIL +-m udp --dport 1;;FAIL +-m udp --dport 1 -p udp;-p udp -m udp --dport 1;OK +-m udp --dport 1 -p 17;-p udp -m udp --dport 1;OK # should we accept this below? -p udp -m udp;=;OK diff --git a/iptables/nft.c b/iptables/nft.c index 430888e8..63468cf3 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1360,6 +1360,9 @@ static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r, return ret; } + if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP) + xtables_error(PARAMETER_PROBLEM, "UDP match requires '-p udp'"); + return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT, udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } @@ -1410,6 +1413,9 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r, return ret; } + if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_TCP) + xtables_error(PARAMETER_PROBLEM, "TCP match requires '-p tcp'"); + if (tcp->flg_mask) { int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask, tcp->invflags & XT_TCP_INV_FLAGS); -- cgit v1.2.3 From 567f6ba105302f57ccb6789dbcfc9e1e2657809a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 22 Dec 2022 17:23:49 +0100 Subject: gitignore: Ignore utils/nfsynproxy Fixes: 9e6928f037823 ("utils: add nfsynproxy tool") Signed-off-by: Phil Sutter --- utils/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/.gitignore b/utils/.gitignore index 6300812b..e508bb32 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -2,3 +2,4 @@ /nfnl_osf.8 /nfbpf_compile /nfbpf_compile.8 +/nfsynproxy -- cgit v1.2.3 From 270e8a1edfea4b6e76f8f507b5a778a94f5309da Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 22 Dec 2022 17:19:05 +0100 Subject: gitignore: Ignore generated ip6tables man pages Fixes: 127eadee563e4 ("Makefile: Generate ip6tables man pages on the fly") Signed-off-by: Phil Sutter --- iptables/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iptables/.gitignore b/iptables/.gitignore index cd7d87b1..245e1245 100644 --- a/iptables/.gitignore +++ b/iptables/.gitignore @@ -1,6 +1,10 @@ /ip6tables +/ip6tables.8 +/ip6tables-apply.8 /ip6tables-save +/ip6tables-save.8 /ip6tables-restore +/ip6tables-restore.8 /ip6tables-static /ip6tables-translate.8 /ip6tables-restore-translate.8 -- cgit v1.2.3 From 85e4de22698dd273fe2b75902f2e006aa90c6f35 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 22 Dec 2022 17:14:34 +0100 Subject: ebtables-translate: Install symlink Make this officially a tool, we have enough test coverage in place. Also update xtables-translate.8 to mention it at least and generate ebtables-translate.8 which points to it. Signed-off-by: Phil Sutter --- iptables/.gitignore | 1 + iptables/Makefile.am | 6 +++--- iptables/xtables-translate.8 | 13 +++++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/iptables/.gitignore b/iptables/.gitignore index 245e1245..8141e34d 100644 --- a/iptables/.gitignore +++ b/iptables/.gitignore @@ -1,3 +1,4 @@ +/ebtables-translate.8 /ip6tables /ip6tables.8 /ip6tables-apply.8 diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 4353dd00..1f37640f 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -69,7 +69,7 @@ dist_pkgdata_DATA = iptables.xslt if ENABLE_NFTABLES man_MANS += iptables-translate.8 ip6tables-translate.8 \ iptables-restore-translate.8 ip6tables-restore-translate.8 \ - xtables-monitor.8 + xtables-monitor.8 ebtables-translate.8 dist_man_MANS = xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ @@ -89,7 +89,7 @@ endif if ENABLE_NFTABLES x_sbin_links = iptables-nft iptables-nft-restore iptables-nft-save \ ip6tables-nft ip6tables-nft-restore ip6tables-nft-save \ - iptables-translate ip6tables-translate \ + iptables-translate ip6tables-translate ebtables-translate \ iptables-restore-translate ip6tables-restore-translate \ arptables-nft arptables \ arptables-nft-restore arptables-restore \ @@ -105,7 +105,7 @@ 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 iptables-restore-translate.8 ip6tables-restore-translate.8: +iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8 ebtables-translate.8: ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@ ip6tables.8 ip6tables-apply.8 ip6tables-restore.8 ip6tables-save.8: diff --git a/iptables/xtables-translate.8 b/iptables/xtables-translate.8 index 3dc72760..a048e8c9 100644 --- a/iptables/xtables-translate.8 +++ b/iptables/xtables-translate.8 @@ -28,9 +28,12 @@ iptables-translate \(em translation tool to migrate from iptables to nftables .P ip6tables-translate \(em translation tool to migrate from ip6tables to nftables +.P +ebtables-translate \(em translation tool to migrate from ebtables 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. +ruleset from \fBiptables(8)\fP, \fBip6tables(8)\fP and \fBebtables(8)\fP to +\fBnftables(8)\fP. The available commands are: @@ -42,9 +45,12 @@ iptables-restore-translate ip6tables-translate .IP \[bu] ip6tables-restore-translate +.IP \[bu] 2 +ebtables-translate .SH USAGE -They take as input the original \fBiptables(8)\fP/\fBip6tables(8)\fP syntax and +They take as input the original +\fBiptables(8)\fP/\fBip6tables(8)\fP/\fBebtables(8)\fP syntax and output the native \fBnftables(8)\fP syntax. The \fBiptables-restore-translate\fP tool reads a ruleset in the syntax @@ -117,8 +123,7 @@ Some (few) extensions may be not supported (or fully-supported) for whatever reason (for example, they were considered obsolete, or we didn't have the time to work on them). -There are no translations available for \fBebtables(8)\fP and -\fBarptables(8)\fP. +There is no translation available for \fBarptables(8)\fP. To get up-to-date information about this, please head to \fBhttps://wiki.nftables.org/\fP. -- cgit v1.2.3 From 1341394f3840e76f94df5578a808cfb849bd4b8b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 10 Jan 2023 17:27:42 +0100 Subject: Makefile: Replace brace expansion According to bash(1), it is not supported by "historical versions of sh". Dash seems to be such a historical version. Reported-by: Pablo Neira Ayuso Fixes: 3822a992bc277 ("Makefile: Fix for 'make distcheck'") Signed-off-by: Phil Sutter --- extensions/GNUmakefile.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index c37e4619..e289adf0 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -106,7 +106,8 @@ uninstall: } clean: - rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c; + rm -f *.o *.oo *.so *.a matches.man targets.man + rm -f initext.c initext4.c initext6.c initextb.c initexta.c rm -f .*.d .*.dd; distclean: clean @@ -243,7 +244,7 @@ distdir: mkdir -p $(distdir) cp -p ${dist_sources} $(distdir)/ cp -p $(wildcard ${srcdir}/lib*.man) $(distdir)/ - cp -p $(srcdir)/*.{t,txlate} $(distdir)/ + cp -p $(wildcard ${srcdir}/*.t ${srcdir}/*.txlate) $(distdir)/ dvi: check: all -- cgit v1.2.3 From 11407d91a1bece630e0e1f2063ce726e4045827d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 10 Jan 2023 17:46:43 +0100 Subject: configure: Bump version for 1.8.9 release Signed-off-by: Phil Sutter --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index ea5d2d49..bc2ed47b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ -AC_INIT([iptables], [1.8.8]) +AC_INIT([iptables], [1.8.9]) # See libtool.info "Libtool's versioning system" -libxtables_vcurrent=18 -libxtables_vage=6 +libxtables_vcurrent=19 +libxtables_vage=7 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) -- cgit v1.2.3 From ed4082a7405a5838c205a34c1559e289949200cc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Jan 2023 14:38:44 +0100 Subject: extensions: NAT: Fix for -Werror=format-security Have to pass either a string literal or format string to xt_xlate_add(). Fixes: f30c5edce0413 ("extensions: Merge SNAT, DNAT, REDIRECT and MASQUERADE") Signed-off-by: Phil Sutter --- extensions/libxt_NAT.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_NAT.c b/extensions/libxt_NAT.c index da9f2201..2a634398 100644 --- a/extensions/libxt_NAT.c +++ b/extensions/libxt_NAT.c @@ -424,7 +424,7 @@ __NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) return 0; - xt_xlate_add(xl, tgt); + xt_xlate_add(xl, "%s", tgt); if (strlen(range_str)) xt_xlate_add(xl, " to %s", range_str); if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { -- cgit v1.2.3 From ca8fb6c21b298b3d96db2bfbf9c74d393bdd4728 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 17 Jan 2023 16:38:43 +0100 Subject: etc: Drop xtables.conf The file is not used since the commit this one fixes. Also it wasn't installed until recently, when commit 3822a992bc277 ("Makefile: Fix for 'make distcheck'") added it in the wrong spot in an attempt to reduce differences between tarballs generated by 'make tarball' and 'make dist'. While being at it, drop stale xtables_config_main() prototype from xtables-multi.h. Fixes: 06fd5e46d46f7 ("xtables: Drop support for /etc/xtables.conf") Signed-off-by: Phil Sutter --- Makefile.am | 2 +- etc/xtables.conf | 74 ------------------------------------------------ iptables/xtables-multi.h | 1 - 3 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 etc/xtables.conf diff --git a/Makefile.am b/Makefile.am index 451c3cb2..299ab46d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ EXTRA_DIST = autogen.sh iptables-test.py xlate-test.py if ENABLE_NFTABLES confdir = $(sysconfdir) -dist_conf_DATA = etc/ethertypes etc/xtables.conf +dist_conf_DATA = etc/ethertypes endif .PHONY: tarball diff --git a/etc/xtables.conf b/etc/xtables.conf deleted file mode 100644 index 3c54ced0..00000000 --- a/etc/xtables.conf +++ /dev/null @@ -1,74 +0,0 @@ -family ipv4 { - table raw { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -300 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -300 - } - - table mangle { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -150 - chain INPUT hook NF_INET_LOCAL_IN prio -150 - chain FORWARD hook NF_INET_FORWARD prio -150 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -150 - chain POSTROUTING hook NF_INET_POST_ROUTING prio -150 - } - - table filter { - chain INPUT hook NF_INET_LOCAL_IN prio 0 - chain FORWARD hook NF_INET_FORWARD prio 0 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 0 - } - - table nat { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -100 - chain INPUT hook NF_INET_LOCAL_IN prio 100 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -100 - chain POSTROUTING hook NF_INET_POST_ROUTING prio 100 - } - - table security { - chain INPUT hook NF_INET_LOCAL_IN prio 50 - chain FORWARD hook NF_INET_FORWARD prio 50 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 50 - } -} - -family ipv6 { - table raw { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -300 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -300 - } - - table mangle { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -150 - chain INPUT hook NF_INET_LOCAL_IN prio -150 - chain FORWARD hook NF_INET_FORWARD prio -150 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -150 - chain POSTROUTING hook NF_INET_POST_ROUTING prio -150 - } - - table filter { - chain INPUT hook NF_INET_LOCAL_IN prio 0 - chain FORWARD hook NF_INET_FORWARD prio 0 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 0 - } - - table nat { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -100 - chain INPUT hook NF_INET_LOCAL_IN prio 100 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -100 - chain POSTROUTING hook NF_INET_POST_ROUTING prio 100 - } - - table security { - chain INPUT hook NF_INET_LOCAL_IN prio 50 - chain FORWARD hook NF_INET_FORWARD prio 50 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 50 - } -} - -family arp { - table filter { - chain INPUT hook NF_ARP_IN prio 0 - chain OUTPUT hook NF_ARP_OUT prio 0 - } -} diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index 94c24d5a..833c11a2 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -20,7 +20,6 @@ extern int xtables_arp_save_main(int, char **); extern int xtables_eb_main(int, char **); extern int xtables_eb_restore_main(int, char **); extern int xtables_eb_save_main(int, char **); -extern int xtables_config_main(int, char **); extern int xtables_monitor_main(int, char **); extern struct xtables_globals arptables_globals; -- cgit v1.2.3 From d6eb6a9fd3878ce4fa01f8d4127f1735988bd07b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 25 Jan 2023 01:51:43 +0100 Subject: Proper fix for "unknown argument" error message While commit 1b8210f848631 kind of fixed the corner-case of invalid short-options packed with others, it broke error reporting for long-options. Revert it and deploy a proper solution: When passing an invalid short-option, e.g. 'iptables -vaL', getopt_long sets the variable 'optopt' to the invalid character's value. Use it for reporting instead of optind if set. To distinguish between invalid options and missing option arguments, ebtables-translate optstring needs adjustment. Fixes: 1b8210f848631 ("ebtables: Fix error message for invalid parameters") Signed-off-by: Phil Sutter --- .../shell/testcases/iptables/0009-unknown-arg_0 | 31 ++++++++++++++++++++++ iptables/xshared.c | 9 ++++--- iptables/xtables-eb-translate.c | 8 ++---- iptables/xtables-eb.c | 17 +++++++----- 4 files changed, 50 insertions(+), 15 deletions(-) create mode 100755 iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 diff --git a/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 new file mode 100755 index 00000000..ac6e7439 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 @@ -0,0 +1,31 @@ +#!/bin/bash + +rc=0 + +check() { + local cmd="$1" + local msg="$2" + + $XT_MULTI $cmd 2>&1 | grep -q "$msg" || { + echo "cmd: $XT_MULTI $1" + echo "exp: $msg" + echo "res: $($XT_MULTI $cmd 2>&1)" + rc=1 + } +} + +cmds="iptables ip6tables" +[[ $XT_MULTI == *xtables-nft-multi ]] && { + cmds+=" ebtables" + cmds+=" iptables-translate" + cmds+=" ip6tables-translate" + cmds+=" ebtables-translate" +} + +for cmd in $cmds; do + check "${cmd} --foo" 'unknown option "--foo"' + check "${cmd} -A" 'option "-A" requires an argument' + check "${cmd} -aL" 'unknown option "-a"' +done + +exit $rc diff --git a/iptables/xshared.c b/iptables/xshared.c index f93529b1..ac51fac5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -192,9 +192,12 @@ static int command_default(struct iptables_command_state *cs, if (cs->c == ':') xtables_error(PARAMETER_PROBLEM, "option \"%s\" " "requires an argument", cs->argv[optind-1]); - if (cs->c == '?') - xtables_error(PARAMETER_PROBLEM, "unknown option " - "\"%s\"", cs->argv[optind-1]); + if (cs->c == '?') { + char optoptstr[3] = {'-', optopt, '\0'}; + + xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"", + optopt ? optoptstr : cs->argv[optind - 1]); + } xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); } diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 13b6b864..0c352720 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -201,7 +201,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char printf("nft "); /* Getopt saves the day */ while ((c = getopt_long(argc, argv, - "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { + "-:A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { cs.c = c; switch (c) { case 'A': /* Add a rule */ @@ -491,11 +491,7 @@ print_zero: continue; default: ebt_check_inverse2(optarg, argc, argv); - - if (ebt_command_default(&cs)) - xtables_error(PARAMETER_PROBLEM, - "Unknown argument: '%s'", - argv[optind - 1]); + ebt_command_default(&cs); if (command != 'A' && command != 'I' && command != 'D') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 7214a767..412b5ccc 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -640,7 +640,16 @@ int ebt_command_default(struct iptables_command_state *cs) return 0; } } - return 1; + if (cs->c == ':') + xtables_error(PARAMETER_PROBLEM, "option \"%s\" " + "requires an argument", cs->argv[optind - 1]); + if (cs->c == '?') { + char optoptstr[3] = {'-', optopt, '\0'}; + + xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"", + optopt ? optoptstr : cs->argv[optind - 1]); + } + xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); } int nft_init_eb(struct nft_handle *h, const char *pname) @@ -1084,11 +1093,7 @@ print_zero: continue; default: ebt_check_inverse2(optarg, argc, argv); - - if (ebt_command_default(&cs)) - xtables_error(PARAMETER_PROBLEM, - "Unknown argument: '%s'", - argv[optind]); + ebt_command_default(&cs); if (command != 'A' && command != 'I' && command != 'D' && command != 'C' && command != 14) -- cgit v1.2.3 From 27d37863a486352511dac385bde8f3d20526be5b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 25 Jan 2023 02:01:56 +0100 Subject: ebtables: Refuse unselected targets' options Unlike legacy, ebtables-nft would allow e.g.: | -t nat -A PREROUTING --to-dst fe:ed:00:00:ba:be While the result is correct, it may mislead users into believing multiple targets are possible per rule. Better follow legacy's behaviour and reject target options unless they have been "enabled" by a previous '-j' option. To achieve this, one needs to distinguish targets from watchers also attached to 'xtables_targets' and otherwise behaving like regular matches. Introduce XTABLES_EXT_WATCHER to mark the two. The above works already, but error messages are misleading when using the now unsupported syntax since target options have been merged already. Solve this by not pre-loading the targets at all, code will just fall back to loading ad '-j' parsing time as iptables does. Note how this also fixes for 'counter' statement being in wrong position of ebtables-translate output. Fixes: fe97f60e5d2a9 ("ebtables-compat: add watchers support") Signed-off-by: Phil Sutter --- extensions/libebt_dnat.txlate | 12 ++++----- extensions/libebt_log.c | 1 + extensions/libebt_mark.txlate | 16 ++++++------ extensions/libebt_nflog.c | 1 + extensions/libebt_snat.txlate | 8 +++--- include/xtables.h | 1 + .../ebtables/0002-ebtables-save-restore_0 | 4 +-- iptables/xtables-eb.c | 29 ++++++++-------------- 8 files changed, 33 insertions(+), 39 deletions(-) diff --git a/extensions/libebt_dnat.txlate b/extensions/libebt_dnat.txlate index 9f305c76..531a22aa 100644 --- a/extensions/libebt_dnat.txlate +++ b/extensions/libebt_dnat.txlate @@ -1,8 +1,8 @@ -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff -nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter' +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT -nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter' +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE -nft 'add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff continue counter' +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff continue' diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 04506219..9f8d1589 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -197,6 +197,7 @@ static int brlog_xlate(struct xt_xlate *xl, static struct xtables_target brlog_target = { .name = "log", .revision = 0, + .ext_flags = XTABLES_EXT_WATCHER, .version = XTABLES_VERSION, .family = NFPROTO_BRIDGE, .size = XT_ALIGN(sizeof(struct ebt_log_info)), diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate index d006e8ac..4ace1a1f 100644 --- a/extensions/libebt_mark.txlate +++ b/extensions/libebt_mark.txlate @@ -1,11 +1,11 @@ -ebtables-translate -A INPUT --mark-set 42 -nft 'add rule bridge filter INPUT meta mark set 0x2a accept counter' +ebtables-translate -A INPUT -j mark --mark-set 42 +nft 'add rule bridge filter INPUT counter meta mark set 0x2a accept' -ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN -nft 'add rule bridge filter INPUT meta mark set meta mark or 0x2a return counter' +ebtables-translate -A INPUT -j mark --mark-or 42 --mark-target RETURN +nft 'add rule bridge filter INPUT counter meta mark set meta mark or 0x2a return' -ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT -nft 'add rule bridge filter INPUT meta mark set meta mark and 0x2a accept counter' +ebtables-translate -A INPUT -j mark --mark-and 42 --mark-target ACCEPT +nft 'add rule bridge filter INPUT counter meta mark set meta mark and 0x2a accept' -ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP -nft 'add rule bridge filter INPUT meta mark set meta mark xor 0x2a drop counter' +ebtables-translate -A INPUT -j mark --mark-xor 42 --mark-target DROP +nft 'add rule bridge filter INPUT counter meta mark set meta mark xor 0x2a drop' diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c index 115e15da..762d6d5d 100644 --- a/extensions/libebt_nflog.c +++ b/extensions/libebt_nflog.c @@ -146,6 +146,7 @@ static int brnflog_xlate(struct xt_xlate *xl, static struct xtables_target brnflog_watcher = { .name = "nflog", .revision = 0, + .ext_flags = XTABLES_EXT_WATCHER, .version = XTABLES_VERSION, .family = NFPROTO_BRIDGE, .size = XT_ALIGN(sizeof(struct ebt_nflog_info)), diff --git a/extensions/libebt_snat.txlate b/extensions/libebt_snat.txlate index 857a6052..37343d3a 100644 --- a/extensions/libebt_snat.txlate +++ b/extensions/libebt_snat.txlate @@ -1,5 +1,5 @@ -ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ --to-source de:ad:00:be:ee:ff -nft 'add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter' +ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ -j snat --to-source de:ad:00:be:ee:ff +nft 'add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 counter ether saddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A POSTROUTING -o someport --to-src de:ad:00:be:ee:ff --snat-target CONTINUE -nft 'add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter' +ebtables-translate -t nat -A POSTROUTING -o someport -j snat --to-src de:ad:00:be:ee:ff --snat-target CONTINUE +nft 'add rule bridge nat POSTROUTING oifname "someport" counter ether saddr set de:ad:0:be:ee:ff continue' diff --git a/include/xtables.h b/include/xtables.h index 4ffc8ec5..087a1d60 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -203,6 +203,7 @@ struct xtables_lmap { enum xtables_ext_flags { XTABLES_EXT_ALIAS = 1 << 0, + XTABLES_EXT_WATCHER = 1 << 1, }; struct xt_xlate; 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 1091a4e8..b4f9728b 100755 --- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 +++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 @@ -38,7 +38,7 @@ $XT_MULTI ebtables -A foo -p IPv6 --ip6-proto tcp -j ACCEPT $XT_MULTI ebtables -A foo --limit 100 --limit-burst 42 -j ACCEPT $XT_MULTI ebtables -A foo --log -$XT_MULTI ebtables -A foo --mark-set 0x23 --mark-target ACCEPT +$XT_MULTI ebtables -A foo -j mark --mark-set 0x23 --mark-target ACCEPT $XT_MULTI ebtables -A foo --nflog $XT_MULTI ebtables -A foo --pkttype-type multicast -j ACCEPT $XT_MULTI ebtables -A foo --stp-type config -j ACCEPT @@ -53,7 +53,7 @@ $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 -j redirect --redirect-target ACCEPT #$XT_MULTI ebtables -t nat -A PREROUTING --to-src fe:ed:ba:be:00:01 $XT_MULTI ebtables -t nat -A OUTPUT -j ACCEPT diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 412b5ccc..3a73e797 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -468,14 +468,14 @@ static void ebt_load_match(const char *name) xtables_error(OTHER_PROBLEM, "Can't alloc memory"); } -static void __ebt_load_watcher(const char *name, const char *typename) +static void ebt_load_watcher(const char *name) { struct xtables_target *watcher; size_t size; watcher = xtables_find_target(name, XTF_TRY_LOAD); if (!watcher) { - fprintf(stderr, "Unable to load %s %s\n", name, typename); + fprintf(stderr, "Unable to load %s watcher\n", name); return; } @@ -496,16 +496,6 @@ static void __ebt_load_watcher(const char *name, const char *typename) xtables_error(OTHER_PROBLEM, "Can't alloc memory"); } -static void ebt_load_watcher(const char *name) -{ - return __ebt_load_watcher(name, "watcher"); -} - -static void ebt_load_target(const char *name) -{ - return __ebt_load_watcher(name, "target"); -} - void ebt_load_match_extensions(void) { opts = ebt_original_options; @@ -522,13 +512,6 @@ void ebt_load_match_extensions(void) ebt_load_watcher("log"); ebt_load_watcher("nflog"); - - ebt_load_target("mark"); - ebt_load_target("dnat"); - ebt_load_target("snat"); - ebt_load_target("arpreply"); - ebt_load_target("redirect"); - ebt_load_target("standard"); } void ebt_add_match(struct xtables_match *m, @@ -633,6 +616,9 @@ int ebt_command_default(struct iptables_command_state *cs) /* Is it a watcher option? */ for (t = xtables_targets; t; t = t->next) { + if (!(t->ext_flags & XTABLES_EXT_WATCHER)) + continue; + if (t->parse && t->parse(cs->c - t->option_offset, cs->argv, ebt_invert, &t->tflags, NULL, &t->t)) { @@ -726,6 +712,11 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, optind = 0; opterr = false; + for (t = xtables_targets; t; t = t->next) { + t->tflags = 0; + t->used = 0; + } + /* Getopt saves the day */ while ((c = getopt_long(argc, argv, EBT_OPTSTRING, opts, NULL)) != -1) { -- cgit v1.2.3 From c254c3fc3952d39738cec93d91355bbf2ed428a6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 26 Jan 2023 02:43:31 +0100 Subject: ebtables-translate: Drop exec_style Apply the changes from commit 816bd1fdecb63 ("ebtables-nft: remove exec_style") to ebtables-translate, too. Signed-off-by: Phil Sutter --- iptables/xtables-eb-translate.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 0c352720..4db10ae6 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -24,9 +24,6 @@ /* * From include/ebtables_u.h */ -#define EXEC_STYLE_PRG 0 -#define EXEC_STYLE_DAEMON 1 - #define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask) extern int ebt_invert; @@ -172,7 +169,6 @@ static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse return ret; } -/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char **table) { char *buffer; @@ -187,7 +183,6 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char }; char command = 'h'; const char *chain = NULL; - int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; struct xtables_rule_match *xtrm_i; struct ebt_match *match; @@ -292,9 +287,6 @@ print_zero: if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "Multiple commands are not allowed"); - if (exec_style == EXEC_STYLE_DAEMON) - xtables_error(PARAMETER_PROBLEM, - "%s %s", prog_name, prog_vers); printf("%s %s\n", prog_name, prog_vers); exit(0); case 'h': -- cgit v1.2.3 From ab9af3ecce355725071f207d5e9c3bc108e58158 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 26 Jan 2023 02:59:59 +0100 Subject: ebtables-translate: Use OPT_* from xshared.h Same as commit db420e268735e ("ebtables: Merge OPT_* flags with xshared ones") but also introduce 'table_set' as a replacement for OPT_TABLE. Signed-off-by: Phil Sutter --- iptables/xtables-eb-translate.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 4db10ae6..49ae6f64 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -68,19 +68,6 @@ static int parse_rule_number(const char *rule) /* Checks whether a command has already been specified */ #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO) -#define OPT_COMMAND 0x01 -#define OPT_TABLE 0x02 -#define OPT_IN 0x04 -#define OPT_OUT 0x08 -#define OPT_JUMP 0x10 -#define OPT_PROTOCOL 0x20 -#define OPT_SOURCE 0x40 -#define OPT_DEST 0x80 -#define OPT_ZERO 0x100 -#define OPT_LOGICALIN 0x200 -#define OPT_LOGICALOUT 0x400 -#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */ - /* Default command line options. Do not mess around with the already * assigned numbers unless you know what you are doing */ extern struct option ebt_original_options[]; @@ -189,6 +176,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char struct xt_cmd_parse p = { .table = *table, }; + bool table_set = false; /* prevent getopt to spoil our error reporting */ opterr = false; @@ -299,13 +287,16 @@ print_zero: if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "Please put the -t option first"); - ebt_check_option2(&flags, OPT_TABLE); + if (table_set) + xtables_error(PARAMETER_PROBLEM, + "Multiple use of same option not allowed"); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) xtables_error(PARAMETER_PROBLEM, "Table name length cannot exceed %d characters", EBT_TABLE_MAXNAMELEN - 1); *table = optarg; p.table = optarg; + table_set = true; break; case 'i': /* Input interface */ case 2 : /* Logical input interface */ @@ -323,7 +314,7 @@ print_zero: xtables_error(PARAMETER_PROBLEM, "Command and option do not match"); if (c == 'i') { - ebt_check_option2(&flags, OPT_IN); + ebt_check_option2(&flags, OPT_VIANAMEIN); if (selected_chain > 2 && selected_chain < NF_BR_BROUTING) xtables_error(PARAMETER_PROBLEM, "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); @@ -343,7 +334,7 @@ print_zero: ebtables_parse_interface(optarg, cs.eb.logical_in); break; } else if (c == 'o') { - ebt_check_option2(&flags, OPT_OUT); + ebt_check_option2(&flags, OPT_VIANAMEOUT); if (selected_chain < 2 || selected_chain == NF_BR_BROUTING) xtables_error(PARAMETER_PROBLEM, "Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); @@ -378,7 +369,7 @@ print_zero: cs.eb.bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { - ebt_check_option2(&flags, OPT_DEST); + ebt_check_option2(&flags, OPT_DESTINATION); if (ebt_check_inverse2(optarg, argc, argv)) cs.eb.invflags |= EBT_IDEST; @@ -389,7 +380,7 @@ print_zero: cs.eb.bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { - ebt_check_option2(&flags, OPT_COUNT); + ebt_check_option2(&flags, OPT_COUNTERS); if (ebt_check_inverse2(optarg, argc, argv)) xtables_error(PARAMETER_PROBLEM, "Unexpected '!' after -c"); -- cgit v1.2.3 From 3f7da77726d4089237d9c0ed1794892ec001879c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 26 Jan 2023 03:07:33 +0100 Subject: ebtables-translate: Ignore '-j CONTINUE' It is default behaviour. Does not hurt here, but reducing diff to xtables-eb.c can't hurt. Signed-off-by: Phil Sutter --- iptables/xtables-eb-translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 49ae6f64..99347c0c 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -355,7 +355,9 @@ print_zero: break; } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); - command_jump(&cs, optarg); + if (strcmp(optarg, "CONTINUE") != 0) { + command_jump(&cs, optarg); + } break; } else if (c == 's') { ebt_check_option2(&flags, OPT_SOURCE); -- cgit v1.2.3 From b51aef061378b34fa9544b1af34021d89a76547a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 26 Jan 2023 03:27:16 +0100 Subject: ebtables-translate: Print flush command after parsing is finished Otherwise, bad calls like 'ebtables-translate -F -F' produce wrong output instead of an error message. Signed-off-by: Phil Sutter --- iptables/xtables-eb-translate.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index 99347c0c..da7e5e3d 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -247,13 +247,6 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char ret = 1; break; case 'F': /* Flush */ - if (p.chain) { - printf("flush chain bridge %s %s\n", p.table, p.chain); - } else { - printf("flush table bridge %s\n", p.table); - } - ret = 1; - break; case 'Z': /* Zero counters */ if (c == 'Z') { if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L')) @@ -506,6 +499,13 @@ print_zero: if (command == 'P') { return 0; + } else if (command == 'F') { + if (p.chain) { + printf("flush chain bridge %s %s\n", p.table, p.chain); + } else { + printf("flush table bridge %s\n", p.table); + } + ret = 1; } else if (command == 'A') { ret = nft_rule_eb_xlate_add(h, &p, &cs, true); if (!ret) -- cgit v1.2.3 From 13a6bd5bb2c03911dc813e0539c676b10680aa74 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 25 Jan 2023 13:52:48 +0100 Subject: tests: xlate: Support testing multiple individual files Simple use-case: run xlate-test for ebtables-nft: | % ./xlate-test.py extensions/libebt_*.txlate The script interpreted all parameters as a single file. Signed-off-by: Phil Sutter --- xlate-test.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/xlate-test.py b/xlate-test.py index 4cb1401b..1b544600 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -241,17 +241,22 @@ def main(): + '/iptables/' + xtables_nft_multi files = tests = passed = failed = errors = 0 - if args.test: - if not args.test.endswith(".txlate"): - args.test += ".txlate" + for test in args.test: + if not test.endswith(".txlate"): + test += ".txlate" try: - with open(args.test, "r") as payload: - files = 1 - tests, passed, failed, errors = run_test(args.test, payload) + with open(test, "r") as payload: + t, p, f, e = run_test(test, payload) + files += 1 + tests += t + passed += p + failed += f + errors += e except IOError: print(red("Error: ") + "test file does not exist", file=sys.stderr) return 99 - else: + + if files == 0: files, tests, passed, failed, errors = load_test_files() if files > 1: @@ -272,6 +277,6 @@ parser.add_argument('-n', '--nft', type=str, default='nft', help='Replay using given nft binary (default: \'%(default)s\')') parser.add_argument('--no-netns', action='store_true', help='Do not run testsuite in own network namespace') -parser.add_argument("test", nargs="?", help="run only the specified test file") +parser.add_argument("test", nargs="*", help="run only the specified test file(s)") args = parser.parse_args() sys.exit(main()) -- cgit v1.2.3 From aa72fad69a7709f3610f1adc4794885c79788d08 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 11 Feb 2023 08:32:49 +0100 Subject: tests: CLUSTERIP: Drop test file The extension was removed from kernel, do not test for it anymore. Keep the code alive though, to not break existing setups. Signed-off-by: Phil Sutter --- extensions/libipt_CLUSTERIP.t | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 extensions/libipt_CLUSTERIP.t diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t deleted file mode 100644 index 30b80167..00000000 --- a/extensions/libipt_CLUSTERIP.t +++ /dev/null @@ -1,4 +0,0 @@ -:INPUT --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK;LEGACY --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK;LEGACY -- cgit v1.2.3 From f5993955ab1d1ef34a0729af2eb58e1eb4f084da Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Feb 2023 21:55:54 +0100 Subject: nft-shared: Lookup matches in iptables_command_state Some matches may turn into multiple nft statements (naturally or via translation). Such statements must parse into a single extension again in order to rebuild the rule as it was. Introduce nft_find_match_in_cs() to iterate through the lists and drop tcp/udp port match caching in struct nft_xt_ctx which is not needed anymore. Note: Match reuse is not enabled unconditionally for all matches, because iptables supports having multiple instances of the same extension. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 70 ++++++++++++++++++++++++++++++--------------------- iptables/nft-shared.h | 4 --- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 4a7b5406..df3cc6ac 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -304,7 +304,7 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned static struct xtables_match * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, - const char *name); + const char *name, bool reuse); static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) { @@ -322,7 +322,7 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct xtables_match *match; uint32_t value; - match = nft_create_match(ctx, ctx->cs, "mark"); + match = nft_create_match(ctx, ctx->cs, "mark", false); if (!match) return -1; @@ -344,7 +344,7 @@ static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct xtables_match *match; uint8_t value; - match = nft_create_match(ctx, ctx->cs, "pkttype"); + match = nft_create_match(ctx, ctx->cs, "pkttype", false); if (!match) return -1; @@ -641,15 +641,39 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) dreg->bitwise.set = true; } +static struct xtables_match * +nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) +{ + struct xtables_rule_match *rm; + struct ebt_match *ebm; + + for (ebm = cs->match_list; ebm; ebm = ebm->next) { + if (ebm->ismatch && + !strcmp(ebm->u.match->m->u.user.name, name)) + return ebm->u.match; + } + for (rm = cs->matches; rm; rm = rm->next) { + if (!strcmp(rm->match->m->u.user.name, name)) + return rm->match; + } + return NULL; +} + static struct xtables_match * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, - const char *name) + const char *name, bool reuse) { struct xtables_match *match; struct xt_entry_match *m; unsigned int size; + if (reuse) { + match = nft_find_match_in_cs(cs, name); + if (match) + return match; + } + match = xtables_find_match(name, XTF_TRY_LOAD, &cs->matches); if (!match) @@ -671,38 +695,26 @@ nft_create_match(struct nft_xt_ctx *ctx, static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs) { - struct xt_udp *udp = ctx->tcpudp.udp; struct xtables_match *match; - if (!udp) { - match = nft_create_match(ctx, cs, "udp"); - if (!match) - return NULL; - - udp = (void*)match->m->data; - ctx->tcpudp.udp = udp; - } + match = nft_create_match(ctx, cs, "udp", true); + if (!match) + return NULL; - return udp; + return (struct xt_udp *)match->m->data; } static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs) { - struct xt_tcp *tcp = ctx->tcpudp.tcp; struct xtables_match *match; - if (!tcp) { - match = nft_create_match(ctx, cs, "tcp"); - if (!match) { - ctx->errmsg = "tcp match extension not found"; - return NULL; - } - tcp = (void*)match->m->data; - ctx->tcpudp.tcp = tcp; + match = nft_create_match(ctx, cs, "tcp", true); + if (!match) { + ctx->errmsg = "tcp match extension not found"; + return NULL; } - - return tcp; + return (struct xt_tcp *)match->m->data; } static void nft_parse_udp_range(struct nft_xt_ctx *ctx, @@ -872,14 +884,14 @@ static void nft_parse_icmp(struct nft_xt_ctx *ctx, switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, cs, "icmp"); + match = nft_create_match(ctx, cs, "icmp", false); break; case NFPROTO_IPV6: if (icmp.type == UINT8_MAX) { ctx->errmsg = "icmp6 code with any type match not supported"; return; } - match = nft_create_match(ctx, cs, "icmp6"); + match = nft_create_match(ctx, cs, "icmp6", false); break; default: ctx->errmsg = "unexpected family for icmp match"; @@ -1640,10 +1652,10 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, */ switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, ctx->cs, "ttl"); + match = nft_create_match(ctx, ctx->cs, "ttl", false); break; case NFPROTO_IPV6: - match = nft_create_match(ctx, ctx->cs, "hl"); + match = nft_create_match(ctx, ctx->cs, "hl", false); break; default: return -1; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 07d39131..b8bc1a6c 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -76,10 +76,6 @@ struct nft_xt_ctx { struct nft_handle *h; uint32_t flags; const char *table; - union { - struct xt_tcp *tcp; - struct xt_udp *udp; - } tcpudp; struct nft_xt_ctx_reg regs[1 + 16]; -- cgit v1.2.3 From 073d4deddd8f3fc5b6c0b6e62b28f5b1895974b1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Feb 2023 22:05:24 +0100 Subject: nft-shared: Use nft_create_match() in one more spot By dropping the per-family 'cs->matches' selection (which is the default anyway), code becomes identical to the function's body. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index df3cc6ac..52e745fe 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1202,16 +1202,13 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); - struct xtables_rule_match **matches; struct xtables_match *match; struct xt_rateinfo *rinfo; - size_t size; switch (ctx->h->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; break; default: fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", @@ -1219,19 +1216,12 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) exit(EXIT_FAILURE); } - match = xtables_find_match("limit", XTF_TRY_LOAD, matches); + match = nft_create_match(ctx, ctx->cs, "limit", false); if (match == NULL) { ctx->errmsg = "limit match extension not found"; return; } - size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; - match->m = xtables_calloc(1, size); - match->m->u.match_size = size; - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - rinfo = (void *)match->m->data; rinfo->avg = XT_LIMIT_SCALE * unit / rate; rinfo->burst = burst; -- cgit v1.2.3 From e69c2b467d7567027db14d48570fe277495ed52f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Feb 2023 22:24:16 +0100 Subject: nft-shared: Simplify using nft_create_match() Perform the nft_family_ops::parse_match call from inside nft_create_match(). It frees callers from having to access the match itself. Then return a pointer to match data instead of the match itself. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 106 +++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 66 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 52e745fe..1b22eb7a 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -301,7 +301,7 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned memset(mask, 0xff, len - 2); } -static struct xtables_match * +static void * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name, bool reuse); @@ -319,15 +319,12 @@ static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { struct xt_mark_mtinfo1 *mark; - struct xtables_match *match; uint32_t value; - match = nft_create_match(ctx, ctx->cs, "mark", false); - if (!match) + mark = nft_create_match(ctx, ctx->cs, "mark", false); + if (!mark) return -1; - mark = (void*)match->m->data; - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) mark->invert = 1; @@ -341,15 +338,12 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { struct xt_pkttype_info *pkttype; - struct xtables_match *match; uint8_t value; - match = nft_create_match(ctx, ctx->cs, "pkttype", false); - if (!match) + pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false); + if (!pkttype) return -1; - pkttype = (void*)match->m->data; - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) pkttype->invert = 1; @@ -659,7 +653,7 @@ nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) return NULL; } -static struct xtables_match * +static void * nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name, bool reuse) @@ -671,7 +665,7 @@ nft_create_match(struct nft_xt_ctx *ctx, if (reuse) { match = nft_find_match_in_cs(cs, name); if (match) - return match; + return match->m->data; } match = xtables_find_match(name, XTF_TRY_LOAD, @@ -689,32 +683,10 @@ nft_create_match(struct nft_xt_ctx *ctx, xs_init_match(match); - return match; -} - -static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs) -{ - struct xtables_match *match; - - match = nft_create_match(ctx, cs, "udp", true); - if (!match) - return NULL; - - return (struct xt_udp *)match->m->data; -} - -static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs) -{ - struct xtables_match *match; + if (ctx->h->ops->parse_match) + ctx->h->ops->parse_match(match, cs); - match = nft_create_match(ctx, cs, "tcp", true); - if (!match) { - ctx->errmsg = "tcp match extension not found"; - return NULL; - } - return (struct xt_tcp *)match->m->data; + return match->m->data; } static void nft_parse_udp_range(struct nft_xt_ctx *ctx, @@ -723,10 +695,12 @@ static void nft_parse_udp_range(struct nft_xt_ctx *ctx, int dport_from, int dport_to, uint8_t op) { - struct xt_udp *udp = nft_udp_match(ctx, cs); + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); - if (!udp) + if (!udp) { + ctx->errmsg = "udp match extension not found"; return; + } if (sport_from >= 0) { switch (op) { @@ -759,10 +733,12 @@ static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, int dport_from, int dport_to, uint8_t op) { - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - if (!tcp) + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; return; + } if (sport_from >= 0) { switch (op) { @@ -823,10 +799,12 @@ static void nft_parse_udp(struct nft_xt_ctx *ctx, int sport, int dport, uint8_t op) { - struct xt_udp *udp = nft_udp_match(ctx, cs); + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); - if (!udp) + if (!udp) { + ctx->errmsg = "udp match extension not found"; return; + } port_match_single_to_range(udp->spts, &udp->invflags, op, sport, XT_UDP_INV_SRCPT); @@ -839,10 +817,12 @@ static void nft_parse_tcp(struct nft_xt_ctx *ctx, int sport, int dport, uint8_t op) { - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - if (!tcp) + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; return; + } port_match_single_to_range(tcp->spts, &tcp->invflags, op, sport, XT_TCP_INV_SRCPT); @@ -855,11 +835,10 @@ static void nft_parse_icmp(struct nft_xt_ctx *ctx, struct nft_xt_ctx_reg *sreg, uint8_t op, const char *data, size_t dlen) { - struct xtables_match *match; struct ipt_icmp icmp = { .type = UINT8_MAX, .code = { 0, UINT8_MAX }, - }; + }, *icmpp; if (dlen < 1) goto out_err_len; @@ -884,25 +863,25 @@ static void nft_parse_icmp(struct nft_xt_ctx *ctx, switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, cs, "icmp", false); + icmpp = nft_create_match(ctx, cs, "icmp", false); break; case NFPROTO_IPV6: if (icmp.type == UINT8_MAX) { ctx->errmsg = "icmp6 code with any type match not supported"; return; } - match = nft_create_match(ctx, cs, "icmp6", false); + icmpp = nft_create_match(ctx, cs, "icmp6", false); break; default: ctx->errmsg = "unexpected family for icmp match"; return; } - if (!match) { + if (!icmpp) { ctx->errmsg = "icmp match extension not found"; return; } - memcpy(match->m->data, &icmp, sizeof(icmp)); + memcpy(icmpp, &icmp, sizeof(icmp)); return; out_err_len: @@ -946,10 +925,12 @@ static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, uint8_t op, uint8_t flags, uint8_t mask) { - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - if (!tcp) + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; return; + } if (op == NFT_CMP_NEQ) tcp->invflags |= XT_TCP_INV_FLAGS; @@ -1202,7 +1183,6 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); - struct xtables_match *match; struct xt_rateinfo *rinfo; switch (ctx->h->family) { @@ -1216,18 +1196,14 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) exit(EXIT_FAILURE); } - match = nft_create_match(ctx, ctx->cs, "limit", false); - if (match == NULL) { + rinfo = nft_create_match(ctx, ctx->cs, "limit", false); + if (!rinfo) { ctx->errmsg = "limit match extension not found"; return; } - rinfo = (void *)match->m->data; rinfo->avg = XT_LIMIT_SCALE * unit / rate; rinfo->burst = burst; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); } static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -1599,7 +1575,6 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs) { - struct xtables_match *match; struct ip6t_hl_info *info; uint8_t hl, mode; int op; @@ -1642,19 +1617,18 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, */ switch (ctx->h->family) { case NFPROTO_IPV4: - match = nft_create_match(ctx, ctx->cs, "ttl", false); + info = nft_create_match(ctx, ctx->cs, "ttl", false); break; case NFPROTO_IPV6: - match = nft_create_match(ctx, ctx->cs, "hl", false); + info = nft_create_match(ctx, ctx->cs, "hl", false); break; default: return -1; } - if (!match) + if (!info) return -1; - info = (void*)match->m->data; info->hop_limit = hl; info->mode = mode; -- cgit v1.2.3 From 914350a4586d2817ca7c4919c53142562f27bdaf Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 3 Feb 2023 18:48:33 +0100 Subject: tests: xlate: Properly split input in replay mode Source command may contain quotes, using shlex.split() does the right thing there. Fixes: 7705b2daa3bdc ("tests: xlate: Use --check to verify replay") Signed-off-by: Phil Sutter --- xlate-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xlate-test.py b/xlate-test.py index 1b544600..09e3b67a 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -64,7 +64,7 @@ def test_one_replay(name, sourceline, expected, result): if sourceline.find(';') >= 0: sourceline, searchline = sourceline.split(';') - srcwords = sourceline.split() + srcwords = shlex.split(sourceline) srccmd = srcwords[0] ipt = srccmd.split('-')[0] -- cgit v1.2.3 From 7e63a66e3f02e127895cfc82415219241e3ff6b3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 1 Feb 2023 01:49:37 +0100 Subject: tests: xlate: Print file names even if specified Since the script now supports running for multiple files given on command line, do not skip printing a status line for each. Signed-off-by: Phil Sutter --- xlate-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xlate-test.py b/xlate-test.py index 09e3b67a..6a116598 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -176,7 +176,7 @@ def run_test(name, payload): result.append(name + ": " + red("Fail")) result.append("nft flush ruleset call failed: " + error) - if (passed == tests) and not args.test: + if (passed == tests): print(name + ": " + green("OK")) if not test_passed: print("\n".join(result), file=sys.stderr) -- cgit v1.2.3 From bb6b243c481f90f7dc4a0bd89187ee2bb823f1f6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 31 Jan 2023 22:28:24 +0100 Subject: extensions: libebt_redirect: Fix target translation While EBT_ACCEPT is the default verdict for ebtables targets, omitting it from translation implicitly converts it into 'continue'. Omit the non-default EBT_CONTINUE instead. Fixes: 24ce7465056ae ("ebtables-compat: add redirect match extension") Signed-off-by: Phil Sutter --- extensions/libebt_redirect.c | 2 +- extensions/libebt_redirect.txlate | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 extensions/libebt_redirect.txlate diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c index 4d4c7a02..389f3ccb 100644 --- a/extensions/libebt_redirect.c +++ b/extensions/libebt_redirect.c @@ -84,7 +84,7 @@ static int brredir_xlate(struct xt_xlate *xl, const struct ebt_redirect_info *red = (const void*)params->target->data; xt_xlate_add(xl, "meta set pkttype host"); - if (red->target != EBT_ACCEPT) + if (red->target != EBT_CONTINUE) xt_xlate_add(xl, " %s ", brredir_verdict(red->target)); return 1; } diff --git a/extensions/libebt_redirect.txlate b/extensions/libebt_redirect.txlate new file mode 100644 index 00000000..f0dd5dea --- /dev/null +++ b/extensions/libebt_redirect.txlate @@ -0,0 +1,8 @@ +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host accept' + +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target RETURN +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host return' + +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target CONTINUE +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host' -- cgit v1.2.3 From 6d1263002c2a9fc6dfa59c764dee767a084d428d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 31 Jan 2023 23:32:50 +0100 Subject: extensions: libebt_redirect: Fix for wrong syntax in translation Meta key comes before 'set' in meta statement. Fixes: 24ce7465056ae ("ebtables-compat: add redirect match extension") Signed-off-by: Phil Sutter --- extensions/libebt_redirect.c | 2 +- extensions/libebt_redirect.txlate | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c index 389f3ccb..7821935e 100644 --- a/extensions/libebt_redirect.c +++ b/extensions/libebt_redirect.c @@ -83,7 +83,7 @@ static int brredir_xlate(struct xt_xlate *xl, { const struct ebt_redirect_info *red = (const void*)params->target->data; - xt_xlate_add(xl, "meta set pkttype host"); + xt_xlate_add(xl, "meta pkttype set host"); if (red->target != EBT_CONTINUE) xt_xlate_add(xl, " %s ", brredir_verdict(red->target)); return 1; diff --git a/extensions/libebt_redirect.txlate b/extensions/libebt_redirect.txlate index f0dd5dea..d073ec77 100644 --- a/extensions/libebt_redirect.txlate +++ b/extensions/libebt_redirect.txlate @@ -1,8 +1,8 @@ ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect -nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host accept' +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host accept' ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target RETURN -nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host return' +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host return' ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target CONTINUE -nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta set pkttype host' +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host' -- cgit v1.2.3 From 744c56bda974caaa274318d2825b3e43b55bf145 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 3 Feb 2023 18:58:36 +0100 Subject: extensions: libebt_ip: Do not use 'ip dscp' for translation Converting from TOS field match to DSCP one is irreversible, so replay testing is not possible. Use a raw payload expression to produce something that translates 1:1 back into an 'ip' match. Fixes: 03ecffe6c2cc0 ("ebtables-compat: add initial translations") Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 4 ++-- extensions/libebt_ip.txlate | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index fd87dae7..8b381aa1 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -442,10 +442,10 @@ static int brip_xlate(struct xt_xlate *xl, brip_xlate_nh(xl, info, EBT_IP_DEST); if (info->bitmask & EBT_IP_TOS) { - xt_xlate_add(xl, "ip dscp "); + xt_xlate_add(xl, "@nh,8,8 "); if (info->invflags & EBT_IP_TOS) xt_xlate_add(xl, "!= "); - xt_xlate_add(xl, "0x%02x ", info->tos & 0x3f); /* remove ECN bits */ + xt_xlate_add(xl, "0x%02x ", info->tos); } if (info->bitmask & EBT_IP_PROTO) { struct protoent *pe; diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index 75c1db24..562e3157 100644 --- a/extensions/libebt_ip.txlate +++ b/extensions/libebt_ip.txlate @@ -5,7 +5,7 @@ ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1 nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter' ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff -nft 'insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter' +nft 'insert rule bridge filter OUTPUT oifname "eth0" @nh,8,8 0xff counter' ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22 nft 'add rule bridge filter FORWARD tcp dport 22 counter' -- cgit v1.2.3 From b860e658200af8fdeced2896a1a6c2f0f0692b70 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 3 Feb 2023 17:37:40 +0100 Subject: extensions: libebt_ip: Translation has to match on ether type On one hand, nft refuses th expression in bridge family if layer3 protocol has not been assured by a previous match. On the other, ebt_ip kernel module will only match on IPv4 packets, so there might be a functional change in the translation versus the original. Instead of just always emitting an 'ether type' match, decide whether it's actually needed - explicit "ip " payload matches (or icmp ones) cause implicit creation of a match on IPv4 by nft. Fixes: 03ecffe6c2cc0 ("ebtables-compat: add initial translations") Signed-off-by: Phil Sutter --- extensions/libebt_ip.c | 21 +++++++++++++++++++++ extensions/libebt_ip.txlate | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index 8b381aa1..68f34bff 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -432,6 +432,24 @@ static void brip_xlate_nh(struct xt_xlate *xl, xtables_ipmask_to_numeric(maskp)); } +static bool may_skip_ether_type_dep(uint8_t flags) +{ + /* these convert to "ip (s|d)addr" matches */ + if (flags & (EBT_IP_SOURCE | EBT_IP_DEST)) + return true; + + /* icmp match triggers implicit ether type dependency in nft */ + if (flags & EBT_IP_ICMP) + return true; + + /* allow if "ip protocol" match is created by brip_xlate() */ + if (flags & EBT_IP_PROTO && + !(flags & (EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP))) + return true; + + return false; +} + static int brip_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { @@ -441,6 +459,9 @@ static int brip_xlate(struct xt_xlate *xl, brip_xlate_nh(xl, info, EBT_IP_SOURCE); brip_xlate_nh(xl, info, EBT_IP_DEST); + if (!may_skip_ether_type_dep(info->bitmask)) + xt_xlate_add(xl, "ether type ip "); + if (info->bitmask & EBT_IP_TOS) { xt_xlate_add(xl, "@nh,8,8 "); if (info->invflags & EBT_IP_TOS) diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index 562e3157..28996832 100644 --- a/extensions/libebt_ip.txlate +++ b/extensions/libebt_ip.txlate @@ -5,13 +5,13 @@ ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1 nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter' ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff -nft 'insert rule bridge filter OUTPUT oifname "eth0" @nh,8,8 0xff counter' +nft 'insert rule bridge filter OUTPUT oifname "eth0" ether type ip @nh,8,8 0xff counter' ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22 -nft 'add rule bridge filter FORWARD tcp dport 22 counter' +nft 'add rule bridge filter FORWARD ether type ip tcp dport 22 counter' ebtables-translate -A FORWARD -p ip --ip-proto udp --ip-sport 1024:65535 -nft 'add rule bridge filter FORWARD udp sport 1024-65535 counter' +nft 'add rule bridge filter FORWARD ether type ip udp sport 1024-65535 counter' ebtables-translate -A FORWARD -p ip --ip-proto 253 nft 'add rule bridge filter FORWARD ip protocol 253 counter' -- cgit v1.2.3 From 267a26363826553280a5928043df30a07cdc63bb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 3 Feb 2023 20:08:09 +0100 Subject: ebtables: ip and ip6 matches depend on protocol match This is consistent with legacy ebtables, also avoids invalid combinations like '-p IPv6 --ip-source 1.2.3.4'. Signed-off-by: Phil Sutter --- iptables/nft-bridge.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 83cbe315..b9983b20 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -104,11 +104,18 @@ static int nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, struct nftnl_rule *r, struct xt_entry_match *m) { - if (!strcmp(m->u.user.name, "802_3") && - !(fw->bitmask & EBT_802_3)) + if (!strcmp(m->u.user.name, "802_3") && !(fw->bitmask & EBT_802_3)) xtables_error(PARAMETER_PROBLEM, "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH"); + if (!strcmp(m->u.user.name, "ip") && fw->ethproto != htons(ETH_P_IP)) + xtables_error(PARAMETER_PROBLEM, + "For IP filtering the protocol must be specified as IPv4."); + + if (!strcmp(m->u.user.name, "ip6") && fw->ethproto != htons(ETH_P_IPV6)) + xtables_error(PARAMETER_PROBLEM, + "For IPv6 filtering the protocol must be specified as IPv6."); + return add_match(h, r, m); } -- cgit v1.2.3 From 68fdf09ecfd1769ec68a7df51f564578dbdc0ddf Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 3 Feb 2023 18:25:21 +0100 Subject: xtables-translate: Support insert with index Translation is pretty simple due to nft's 'insert rule ... index' support. Testing the translation is sadly not: index 1 vanishes (as it should), higher indexes are rejected in replay mode since no rules previously exist. Signed-off-by: Phil Sutter --- extensions/libebt_ip.txlate | 2 +- iptables/xtables-translate.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index 28996832..44ce9276 100644 --- a/extensions/libebt_ip.txlate +++ b/extensions/libebt_ip.txlate @@ -4,7 +4,7 @@ nft 'add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept' ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1 nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter' -ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff +ebtables-translate -I OUTPUT -p ip -o eth0 --ip-tos 0xff nft 'insert rule bridge filter OUTPUT oifname "eth0" ether type ip @nh,8,8 0xff counter' ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22 diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 22b2fbc8..88e0a6b6 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -173,6 +173,8 @@ static int nft_rule_xlate_add(struct nft_handle *h, tick, append ? "add" : "insert", family2str[h->family], p->table, p->chain); + if (!append && p->rulenum > 1) + printf("index %d ", p->rulenum); printf("%s%s\n", xt_xlate_rule_get(xl), tick); -- cgit v1.2.3 From f7c8d896f3305471746a8690f73587a65854d8fa Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 21 Feb 2023 12:19:42 -0500 Subject: xt_sctp: add the missing chunk types in sctp_help Add the missing chunk types in sctp_help(), so that the help cmd can display these chunk types as below: # iptables -p sctp --help chunktypes - ... I_DATA RE_CONFIG PAD ... I_FORWARD_TSN ALL NONE Fixes: 6b04d9c34e25 ("xt_sctp: support a couple of new chunk types") Signed-off-by: Xin Long Signed-off-by: Phil Sutter --- extensions/libxt_sctp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index fe5f5621..6e2b2745 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -50,7 +50,7 @@ static void sctp_help(void) " --dport ...\n" "[!] --chunk-types (all|any|none) (chunktype[:flags])+ match if all, any or none of\n" " chunktypes are present\n" -"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN ALL NONE\n"); +"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN ALL NONE\n"); } static const struct option sctp_opts[] = { -- cgit v1.2.3 From 8030e5444681e16ac2f481ddad73e33fab376147 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 22 Feb 2023 16:36:16 +0100 Subject: include: Add missing linux/netfilter/xt_LOG.h When merging IP-version-specific LOG extensions, a dependency to that header was introduced without caching it. Fix this and drop the now unused ip{,6}t_LOG.h files. Reported-by: Thomas Devoogdt Fixes: 87e4f1bf0b87b ("extensions: libip*t_LOG: Merge extensions") Signed-off-by: Phil Sutter --- include/linux/netfilter/xt_LOG.h | 20 ++++++++++++++++++++ include/linux/netfilter_ipv4/ipt_LOG.h | 19 ------------------- include/linux/netfilter_ipv6/ip6t_LOG.h | 19 ------------------- 3 files changed, 20 insertions(+), 38 deletions(-) create mode 100644 include/linux/netfilter/xt_LOG.h delete mode 100644 include/linux/netfilter_ipv4/ipt_LOG.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_LOG.h diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h new file mode 100644 index 00000000..167d4ddd --- /dev/null +++ b/include/linux/netfilter/xt_LOG.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _XT_LOG_H +#define _XT_LOG_H + +/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */ +#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define XT_LOG_TCPOPT 0x02 /* Log TCP options */ +#define XT_LOG_IPOPT 0x04 /* Log IP options */ +#define XT_LOG_UID 0x08 /* Log UID owning local socket */ +#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define XT_LOG_MASK 0x2f + +struct xt_log_info { + unsigned char level; + unsigned char logflags; + char prefix[30]; +}; + +#endif /* _XT_LOG_H */ diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h deleted file mode 100644 index dcdbadf9..00000000 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IPT_LOG_H -#define _IPT_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IPT_LOG_IPOPT 0x04 /* Log IP options */ -#define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ -#define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IPT_LOG_MASK 0x2f - -struct ipt_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h deleted file mode 100644 index 9dd5579e..00000000 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IP6T_LOG_H -#define _IP6T_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IP6T_LOG_IPOPT 0x04 /* Log IP options */ -#define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ -#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ -#define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IP6T_LOG_MASK 0x2f - -struct ip6t_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ -- cgit v1.2.3 From 5fd85822bd12a02f1a921243f605fc6238d705b4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Feb 2023 18:09:25 +0100 Subject: nft-restore: Fix for deletion of new, referenced rule Combining multiple corner-cases here: * Insert a rule before another new one which is not the first. Triggers NFTNL_RULE_ID assignment of the latter. * Delete the referenced new rule in the same batch again. Causes overwriting of the previously assigned RULE_ID. Consequently, iptables-nft-restore fails during *insert*, because the reference is dangling. Reported-by: Eric Garver Fixes: 760b35b46e4cc ("nft: Fix for add and delete of same rule in single batch") Signed-off-by: Phil Sutter Tested-by: Eric Garver --- iptables/nft.c | 3 ++- .../shell/testcases/ipt-restore/0003-restore-ordering_0 | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/iptables/nft.c b/iptables/nft.c index 63468cf3..5896fd41 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2343,7 +2343,8 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) nftnl_rule_list_del(r); - if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)) + if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE) && + !nftnl_rule_get_u32(r, NFTNL_RULE_ID)) nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id); obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 index 3f1d229e..5482b7ea 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 @@ -123,3 +123,19 @@ EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT -A FORWARD -m comment --comment "rule 3" -j ACCEPT' diff -u -Z <(echo -e "$EXPECT") <(ipt_show) + +# test adding, referencing and deleting the same rule in a batch + +$XT_MULTI iptables-restore < Date: Tue, 14 Mar 2023 22:36:50 +0100 Subject: xtables-eb: fix crash when opts isn't reallocated opts may point to statically allocated memory. This fixes abort() from libc. Signed-off-by: Florian Westphal --- iptables/xtables-eb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 3a73e797..068dffd2 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -675,7 +675,8 @@ void nft_fini_eb(struct nft_handle *h) free(target->t); } - free(opts); + if (opts != ebt_original_options) + free(opts); nft_fini(h); xtables_fini(); -- cgit v1.2.3 From ad84e8870ef27bfc662edc0caedd74dac82e1c9d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Mar 2023 22:44:53 +0100 Subject: iptables-nft: make builtin tables static Only used in nft.c. Signed-off-by: Florian Westphal --- iptables/nft.c | 6 +++--- iptables/nft.h | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 5896fd41..5ef5335a 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -434,7 +434,7 @@ static void batch_chain_flush(struct nft_handle *h, } } -const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { [NFT_TABLE_RAW] = { .name = "raw", .type = NFT_TABLE_RAW, @@ -571,7 +571,7 @@ const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { #include -const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", .type = NFT_TABLE_FILTER, @@ -594,7 +594,7 @@ const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { #include -const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", .type = NFT_TABLE_FILTER, diff --git a/iptables/nft.h b/iptables/nft.h index caff1fde..56005863 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -117,10 +117,6 @@ struct nft_handle { } error; }; -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); -- cgit v1.2.3 From 8758e5577c4e40b0f3c7f32da28d385f6278a523 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 15 Mar 2023 08:33:39 +0100 Subject: iptables-nft: remove unused function argument Not used, all callers pass NULL. Signed-off-by: Florian Westphal --- iptables/nft-arp.c | 2 +- iptables/nft-cmd.c | 2 +- iptables/nft-cmd.h | 2 +- iptables/nft-ipv4.c | 2 +- iptables/nft-ipv6.c | 2 +- iptables/xtables-eb.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 210f43d2..8963573a 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -708,7 +708,7 @@ nft_arp_add_entry(struct nft_handle *h, cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; if (append) { - ret = nft_cmd_rule_append(h, chain, table, cs, NULL, + ret = nft_cmd_rule_append(h, chain, table, cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index f16ea0e6..7b2fc3a5 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -92,7 +92,7 @@ static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd) int nft_cmd_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, - void *ref, bool verbose) + bool verbose) { struct nft_cmd *cmd; diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h index c0f84636..ae5908d8 100644 --- a/iptables/nft-cmd.h +++ b/iptables/nft-cmd.h @@ -37,7 +37,7 @@ void nft_cmd_free(struct nft_cmd *cmd); int nft_cmd_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, - void *ref, bool verbose); + bool verbose); int nft_cmd_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, int rulenum, bool verbose); diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index dcc4a8ed..fadadd2e 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -370,7 +370,7 @@ nft_ipv4_add_entry(struct nft_handle *h, if (append) { ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, verbose); + cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, rulenum, verbose); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index e9892185..85bb683f 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -331,7 +331,7 @@ nft_ipv6_add_entry(struct nft_handle *h, &args->d.mask.v6[j], sizeof(struct in6_addr)); if (append) { ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, verbose); + cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, rulenum, verbose); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 068dffd2..bf35f52b 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -99,7 +99,7 @@ append_entry(struct nft_handle *h, int ret = 1; if (append) - ret = nft_cmd_rule_append(h, chain, table, cs, NULL, verbose); + ret = nft_cmd_rule_append(h, chain, table, cs, verbose); else ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose); -- cgit v1.2.3 From 09f0bfe2032454d21e3650e7ac75c4dc53f3c881 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Gonzalez Date: Sat, 14 Jan 2023 21:59:47 +0100 Subject: iptables-test.py: make explicit use of python3 In most distros 'python' means python2, which is not available anywhere. This is a problem when, for example, building the Debian package. This script is called as part of the build but 'python' is not available. Mention python3 explictly. The script runs just fine in python3. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Florian Westphal --- iptables-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables-test.py b/iptables-test.py index de1e1e95..ef0a35d3 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # (C) 2012-2013 by Pablo Neira Ayuso # -- cgit v1.2.3 From 78850e7dba64a949c440dbdbe557f59409c6db48 Mon Sep 17 00:00:00 2001 From: Markus Boehme Date: Mon, 3 Apr 2023 23:13:47 +0200 Subject: ip6tables: Fix checking existence of rule Pass the proper entry size when creating a match mask for checking the existence of a rule. Failing to do so causes wrong results. Reported-by: Jonathan Caicedo Fixes: eb2546a846776 ("xshared: Share make_delete_mask() between ip{,6}tables") Signed-off-by: Markus Boehme Signed-off-by: Phil Sutter --- iptables/ip6tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 345af451..9afc32c1 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -331,7 +331,7 @@ check_entry(const xt_chainlabel chain, struct ip6t_entry *fw, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target, sizeof(fw)); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; fw->ipv6.smsk = smasks[i]; -- cgit v1.2.3 From aed58f545bec0712bcdbe14e2b8386db0c650a91 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 2 Apr 2023 23:29:40 +0000 Subject: build: use pkg-config for libpcap If building statically, with libpcap built with libnl support, linking will fail, as the compiler won't be able to find the libnl symbols since static libraries don't contain dependency information. To fix this, use pkg-config to find the flags for linking libpcap, since the pkg-config files contain the neccesary dependency information. autoconf will add code to the configure script for initializing pkg-config the first time it seems PKG_CHECK_MODULES, so make the libnfnetlink check the first one in the script, so the initialization code is run unconditionally. Signed-off-by: Alyssa Ross Signed-off-by: Phil Sutter --- configure.ac | 9 +++++---- utils/Makefile.am | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index bc2ed47b..488c01eb 100644 --- a/configure.ac +++ b/configure.ac @@ -113,14 +113,15 @@ AM_CONDITIONAL([ENABLE_SYNCONF], [test "$enable_nfsynproxy" = "yes"]) AM_CONDITIONAL([ENABLE_NFTABLES], [test "$enable_nftables" = "yes"]) AM_CONDITIONAL([ENABLE_CONNLABEL], [test "$enable_connlabel" = "yes"]) -if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then - AC_CHECK_LIB(pcap, pcap_compile,, AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool)) -fi - PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0], [nfnetlink=1], [nfnetlink=0]) AM_CONDITIONAL([HAVE_LIBNFNETLINK], [test "$nfnetlink" = 1]) +if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then + PKG_CHECK_MODULES([libpcap], [libpcap], [], [ + AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool)]) +fi + if test "x$enable_nftables" = "xyes"; then PKG_CHECK_MODULES([libmnl], [libmnl >= 1.0], [mnl=1], [mnl=0]) diff --git a/utils/Makefile.am b/utils/Makefile.am index e9eec48f..34056514 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -2,7 +2,7 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \ - -I${top_srcdir}/include ${libnfnetlink_CFLAGS} + -I${top_srcdir}/include ${libnfnetlink_CFLAGS} ${libpcap_CFLAGS} AM_LDFLAGS = ${regular_LDFLAGS} sbin_PROGRAMS = @@ -25,12 +25,12 @@ endif if ENABLE_BPFC man_MANS += nfbpf_compile.8 sbin_PROGRAMS += nfbpf_compile -nfbpf_compile_LDADD = -lpcap +nfbpf_compile_LDADD = ${libpcap_LIBS} endif if ENABLE_SYNCONF sbin_PROGRAMS += nfsynproxy -nfsynproxy_LDADD = -lpcap +nfsynproxy_LDADD = ${libpcap_LIBS} endif CLEANFILES = nfnl_osf.8 nfbpf_compile.8 -- cgit v1.2.3 From 545310d9ed412f895a8aad757f6f6324b66d062f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 4 Apr 2023 11:45:43 +0200 Subject: include: update nf_tables uapi header Taken from nf-next. Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- include/linux/netfilter/nf_tables.h | 59 +++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index e94d1fa5..c4d4d8e4 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -97,6 +97,14 @@ enum nft_verdicts { * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes) * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes) * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes) + * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes) + * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes) + * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes) + * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes) + * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes) + * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes) + * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes) + * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes) */ enum nf_tables_msg_types { NFT_MSG_NEWTABLE, @@ -124,6 +132,14 @@ enum nf_tables_msg_types { NFT_MSG_NEWFLOWTABLE, NFT_MSG_GETFLOWTABLE, NFT_MSG_DELFLOWTABLE, + NFT_MSG_GETRULE_RESET, + NFT_MSG_DESTROYTABLE, + NFT_MSG_DESTROYCHAIN, + NFT_MSG_DESTROYRULE, + NFT_MSG_DESTROYSET, + NFT_MSG_DESTROYSETELEM, + NFT_MSG_DESTROYOBJ, + NFT_MSG_DESTROYFLOWTABLE, NFT_MSG_MAX, }; @@ -669,7 +685,7 @@ enum nft_range_ops { * enum nft_range_attributes - nf_tables range expression netlink attributes * * @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers) - * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops) + * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_range_ops) * @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes) * @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes) */ @@ -753,11 +769,14 @@ enum nft_dynset_attributes { * @NFT_PAYLOAD_LL_HEADER: link layer header * @NFT_PAYLOAD_NETWORK_HEADER: network header * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header + * @NFT_PAYLOAD_INNER_HEADER: inner header / payload */ enum nft_payload_bases { NFT_PAYLOAD_LL_HEADER, NFT_PAYLOAD_NETWORK_HEADER, NFT_PAYLOAD_TRANSPORT_HEADER, + NFT_PAYLOAD_INNER_HEADER, + NFT_PAYLOAD_TUN_HEADER, }; /** @@ -777,6 +796,32 @@ enum nft_payload_csum_flags { NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0), }; +enum nft_inner_type { + NFT_INNER_UNSPEC = 0, + NFT_INNER_VXLAN, + NFT_INNER_GENEVE, +}; + +enum nft_inner_flags { + NFT_INNER_HDRSIZE = (1 << 0), + NFT_INNER_LL = (1 << 1), + NFT_INNER_NH = (1 << 2), + NFT_INNER_TH = (1 << 3), +}; +#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \ + NFT_INNER_NH | NFT_INNER_TH) + +enum nft_inner_attributes { + NFTA_INNER_UNSPEC, + NFTA_INNER_NUM, + NFTA_INNER_TYPE, + NFTA_INNER_FLAGS, + NFTA_INNER_HDRSIZE, + NFTA_INNER_EXPR, + __NFTA_INNER_MAX +}; +#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1) + /** * enum nft_payload_attributes - nf_tables payload expression netlink attributes * @@ -833,7 +878,7 @@ enum nft_exthdr_op { * @NFTA_EXTHDR_LEN: extension header length (NLA_U32) * @NFTA_EXTHDR_FLAGS: extension header flags (NLA_U32) * @NFTA_EXTHDR_OP: option match type (NLA_U32) - * @NFTA_EXTHDR_SREG: option match type (NLA_U32) + * @NFTA_EXTHDR_SREG: source register (NLA_U32: nft_registers) */ enum nft_exthdr_attributes { NFTA_EXTHDR_UNSPEC, @@ -886,6 +931,7 @@ enum nft_exthdr_attributes { * @NFT_META_TIME_HOUR: hour of day (in seconds) * @NFT_META_SDIF: slave device interface index * @NFT_META_SDIFNAME: slave device interface name + * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit */ enum nft_meta_keys { NFT_META_LEN, @@ -896,7 +942,8 @@ enum nft_meta_keys { NFT_META_OIF, NFT_META_IIFNAME, NFT_META_OIFNAME, - NFT_META_IIFTYPE, + NFT_META_IFTYPE, +#define NFT_META_IIFTYPE NFT_META_IFTYPE NFT_META_OIFTYPE, NFT_META_SKUID, NFT_META_SKGID, @@ -923,6 +970,8 @@ enum nft_meta_keys { NFT_META_TIME_HOUR, NFT_META_SDIF, NFT_META_SDIFNAME, + NFT_META_BRI_BROUTE, + __NFT_META_IIFTYPE, }; /** @@ -1213,10 +1262,10 @@ enum nft_last_attributes { /** * enum nft_log_attributes - nf_tables log expression netlink attributes * - * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32) + * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U16) * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING) * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32) - * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32) + * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U16) * @NFTA_LOG_LEVEL: log level (NLA_U32) * @NFTA_LOG_FLAGS: logging flags (NLA_U32) */ -- cgit v1.2.3 From 73611d5582e72367a698faf1b5301c836e981465 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 4 Apr 2023 11:45:44 +0200 Subject: ebtables-nft: add broute table emulation Use new 'meta broute set 1' to emulate -t broute. If '-t broute' is given, automatically translate -j DROP to 'meta broute set 1 accept' internally. Reverse translation zaps the broute and pretends verdict was DROP. Note that BROUTING is internally handled via PREROUTING, i.e. 'redirect' and 'nat' targets are not available, they will need to be emulated via nft expressions. Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- iptables/ebtables-nft.8 | 42 ++++++++++++++-------- iptables/nft-bridge.c | 36 +++++++++++++++++++ iptables/nft-shared.c | 39 ++++++++++++++------ iptables/nft-shared.h | 3 ++ iptables/nft.c | 13 +++++++ iptables/nft.h | 3 +- .../shell/testcases/ebtables/0001-ebtables-basic_0 | 4 +-- 7 files changed, 112 insertions(+), 28 deletions(-) diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index d75aae24..0304b508 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -55,7 +55,7 @@ It is analogous to the 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 +There are three 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 @@ -81,7 +81,10 @@ an 'extension' (see below) or a jump to a user-defined chain. .B ACCEPT means to let the frame through. .B DROP -means the frame has to be dropped. +means the frame has to be dropped. In the +.BR BROUTING " chain however, the " ACCEPT " and " DROP " target have different" +meanings (see the info provided for the +.BR -t " option)." .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 @@ -93,17 +96,13 @@ 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, +As stated earlier, the table names are +.BR filter ", " nat " and " broute . +Of these 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. +If you are working with a table other than filter, you will need to provide +the -t argument. Moreover, the -t argument must be the +first argument on the ebtables command line, if used. .TP .B "-t, --table" .br @@ -131,6 +130,23 @@ 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. +.br +.br +.B broute +is used to make a brouter, it has one built-in chain: +.BR BROUTING . +The targets +.BR DROP " and " ACCEPT +have a special meaning in the broute table (these names are used for +compatibility reasons with ebtables-legacy). +.B DROP +actually means the frame has to be routed, while +.B ACCEPT +means the frame has to be bridged. The +.B BROUTING +chain is traversed very early. +Normally those frames +would be bridged, but you can decide otherwise here. .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 @@ -1059,8 +1075,6 @@ arp message and the hardware address length in the arp header is 6 bytes. .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 .B string match. Further, support for atomic-options .RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit ) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index b9983b20..22860d6b 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -95,8 +95,44 @@ static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, add_cmp_ptr(r, op, iface, iface_len + 1, reg); } +static int add_meta_broute(struct nftnl_rule *r) +{ + struct nftnl_expr *expr; + + expr = nftnl_expr_alloc("immediate"); + if (expr == NULL) + return -1; + + nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01); + nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1); + nftnl_rule_add_expr(r, expr); + + expr = nftnl_expr_alloc("meta"); + if (expr == NULL) + return -1; + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE); + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01); + + nftnl_rule_add_expr(r, expr); + return 0; +} + static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) { + const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); + + if (cs->target && + table && strcmp(table, "broute") == 0) { + if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) { + int ret = add_meta_broute(r); + + if (ret) + return ret; + + cs->jumpto = "ACCEPT"; + } + } + return add_action(r, cs, false); } diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 1b22eb7a..c19d78e4 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -511,8 +511,24 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) *inv = (op == NFT_CMP_NEQ); } -static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, - struct nftnl_expr *e) +static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, + struct nft_xt_ctx_reg *sreg) +{ + if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { + ctx->errmsg = "meta sreg is not an immediate"; + return false; + } + + if (sreg->immediate.data[0] == 0) { + ctx->errmsg = "meta sreg immediate is 0"; + return false; + } + + return true; +} + +static void nft_parse_meta_set(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) { struct xtables_target *target; struct nft_xt_ctx_reg *sreg; @@ -528,18 +544,17 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx, switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) { case NFT_META_NFTRACE: - if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { - ctx->errmsg = "meta nftrace but reg not immediate"; + if (!nft_parse_meta_set_common(ctx, sreg)) return; - } - - if (sreg->immediate.data[0] == 0) { - ctx->errmsg = "trace is cleared"; - return; - } targname = "TRACE"; break; + case NFT_META_BRI_BROUTE: + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + ctx->cs->jumpto = "DROP"; + return; default: ctx->errmsg = "meta sreg key not supported"; return; @@ -568,7 +583,7 @@ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) struct nft_xt_ctx_reg *reg; if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { - nft_meta_set_to_target(ctx, e); + nft_parse_meta_set(ctx, e); return; } @@ -1145,6 +1160,8 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) /* Standard target? */ switch(verdict) { case NF_ACCEPT: + if (cs->jumpto && strcmp(ctx->table, "broute") == 0) + break; cs->jumpto = "ACCEPT"; break; case NF_DROP: diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index b8bc1a6c..2c4c0d90 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -61,6 +61,9 @@ struct nft_xt_ctx_reg { struct { uint32_t key; } meta_dreg; + struct { + uint32_t key; + } meta_sreg; }; struct { diff --git a/iptables/nft.c b/iptables/nft.c index 5ef5335a..1cb104e7 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -643,6 +643,19 @@ static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { }, }, }, + [NFT_TABLE_BROUTE] = { + .name = "broute", + .type = NFT_TABLE_BROUTE, + .chains = { + { + .name = "BROUTING", + .type = "filter", + .prio = NF_BR_PRI_FIRST, + .hook = NF_BR_PRE_ROUTING, + }, + }, + }, + }; static int nft_table_builtin_add(struct nft_handle *h, diff --git a/iptables/nft.h b/iptables/nft.h index 56005863..1d18982d 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -14,8 +14,9 @@ enum nft_table_type { NFT_TABLE_RAW, NFT_TABLE_FILTER, NFT_TABLE_NAT, + NFT_TABLE_BROUTE, }; -#define NFT_TABLE_MAX (NFT_TABLE_NAT + 1) +#define NFT_TABLE_MAX (NFT_TABLE_BROUTE + 1) struct builtin_chain { const char *name; diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 index 6f11bd12..bae0de7d 100755 --- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 +++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 @@ -15,13 +15,13 @@ get_entries_count() { # (chain) set -x -for t in filter nat;do +for t in filter nat broute; do $XT_MULTI ebtables -t $t -L || exit 1 $XT_MULTI ebtables -t $t -X || exit 1 $XT_MULTI ebtables -t $t -F || exit 1 done -for t in broute foobar ;do +for t in foobar; do $XT_MULTI ebtables -t $t -L && $XT_MULTI ebtables -t $t -X && $XT_MULTI ebtables -t $t -F -- cgit v1.2.3 From 0c2dcbf984939d8473e0b429b41e41a36c8a64da Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 5 Apr 2023 13:18:24 +0200 Subject: tests: shell: Test for false-positive rule check Rule comparison in legacy ip6tables was broken by commit eb2546a846776 ("xshared: Share make_delete_mask() between ip{,6}tables"): A part of the rules' data was masked out for comparison by accident. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/ip6tables/0005-rule-check_0 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 diff --git a/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 new file mode 100755 index 00000000..cc8215bf --- /dev/null +++ b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Test the fix in commit 78850e7dba64a ("ip6tables: Fix checking existence of +# rule"). Happens with legacy ip6tables only, but testing ip6tables-nft doesn't +# hurt. +# +# Code taken from https://bugzilla.netfilter.org/show_bug.cgi?id=1667 +# Thanks to Jonathan Caicedo for providing it. + +RULE='-p tcp --dport 81 -j DNAT --to-destination [::1]:81' + +$XT_MULTI ip6tables -t nat -N testchain || exit 1 +$XT_MULTI ip6tables -t nat -A testchain $RULE || exit 1 +$XT_MULTI ip6tables -t nat -C testchain $RULE || exit 1 + +$XT_MULTI ip6tables -t nat -C testchain ${RULE//81/82} 2>/dev/null && exit 1 +exit 0 -- cgit v1.2.3 From a591f48302e459d079e052b423885ae5eef4fa63 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Apr 2023 15:53:43 +0200 Subject: utils: nfbpf_compile: Replace pcap_compile_nopcap() The function is deprecated. Eliminate the warning by use of pcap_open_dead(), pcap_compile() and pcap_close() just how pcap_compile_nopcap() is implemented internally in libpcap. Signed-off-by: Phil Sutter --- utils/nfbpf_compile.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/utils/nfbpf_compile.c b/utils/nfbpf_compile.c index 2c46c7b0..c9e763dc 100644 --- a/utils/nfbpf_compile.c +++ b/utils/nfbpf_compile.c @@ -17,6 +17,7 @@ int main(int argc, char **argv) struct bpf_program program; struct bpf_insn *ins; int i, dlt = DLT_RAW; + pcap_t *pcap; if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: %s [link] ''\n\n" @@ -36,9 +37,15 @@ int main(int argc, char **argv) } } - if (pcap_compile_nopcap(65535, dlt, &program, argv[argc - 1], 1, + pcap = pcap_open_dead(dlt, 65535); + if (!pcap) { + fprintf(stderr, "Memory allocation failure\n"); + return 1; + } + if (pcap_compile(pcap, &program, argv[argc - 1], 1, PCAP_NETMASK_UNKNOWN)) { fprintf(stderr, "Compilation error\n"); + pcap_close(pcap); return 1; } @@ -50,6 +57,7 @@ int main(int argc, char **argv) printf("%u %u %u %u\n", ins->code, ins->jt, ins->jf, ins->k); pcap_freecode(&program); + pcap_close(pcap); return 0; } -- cgit v1.2.3 From 465470184950d9035dcd1101c1f413f8a2051427 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 29 Mar 2023 16:22:16 +0200 Subject: nft-shared: Drop unused include Code does not refer to struct xt_comment_info anymore. Fixes: 3bb497c61d743 ("xtables: Fix for deleting rules with comment") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index c19d78e4..79f6a7d3 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From 092e4b022152addc94524e2ba0cb608dac1a3a08 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Apr 2023 14:33:43 +0200 Subject: arptables: Fix parsing of inverted 'arp operation' match The wrong bit was set in 'invflags', probably due to copy'n'paste from the previous case. Fixes: 84909d171585d ("xtables: bootstrap ARP compatibility layer for nftables") Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 8963573a..a8e49f44 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -244,7 +244,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, fw->arp.arhln = ar_hln; fw->arp.arhln_mask = 0xff; if (inv) - fw->arp.invflags |= IPT_INV_ARPOP; + fw->arp.invflags |= IPT_INV_ARPHLN; break; case offsetof(struct arphdr, ar_pln): get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); -- cgit v1.2.3 From 79f93b0943fa0e46ba29bb476362634509eb594e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Apr 2023 14:37:47 +0200 Subject: arptables: Don't omit standard matches if inverted Inverted --h-len and --h-type matches were omitted from output by accident if they matched on their standard value. Fixes: 84331e3ed3f8e ("arptables-nft: Don't print default h-len/h-type values") Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index a8e49f44..3236e2f5 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -408,7 +408,8 @@ after_devsrc: after_devdst: - if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) { + if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 || + fw->arp.invflags & IPT_INV_ARPHLN) { printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN ? "! " : ""); printf("--h-length %d", fw->arp.arhln); @@ -432,7 +433,8 @@ after_devdst: sep = " "; } - if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) { + if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) || + fw->arp.invflags & IPT_INV_ARPHRD) { uint16_t tmp = ntohs(fw->arp.arhrd); printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD -- cgit v1.2.3 From 90a7a183a208b691810b8519cc57d3d9d3b7eb60 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Apr 2023 14:41:08 +0200 Subject: xshared: Fix parsing of option arguments in same word When merging commandline parsers, a decision between 'argv[optind - 1]' and 'optarg' had to be made in some spots. While the implementation of check_inverse() required the former, use of the latter allows for the common syntax of '--opt=arg' or even '-oarg' as 'optarg' will point at the suffix while 'argv[optind - 1]' will just point at the following option. Fix the mess by making check_inverse() update optarg pointer if needed so calling code may refer to and always correct 'optarg'. Fixes: 0af80a91b0a98 ("nft: Merge xtables-arp-standalone.c into xtables-standalone.c") Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1677 Signed-off-by: Phil Sutter --- extensions/libarpt_standard.t | 2 ++ extensions/libxt_standard.t | 3 +++ iptables/xshared.c | 61 +++++++++++++++++++++---------------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/extensions/libarpt_standard.t b/extensions/libarpt_standard.t index e84a00b7..007fa2b8 100644 --- a/extensions/libarpt_standard.t +++ b/extensions/libarpt_standard.t @@ -12,3 +12,5 @@ -i lo --destination-mac 11:22:33:44:55:66;-i lo --dst-mac 11:22:33:44:55:66;OK --source-mac Unicast;--src-mac 00:00:00:00:00:00/01:00:00:00:00:00;OK ! --src-mac Multicast;! --src-mac 01:00:00:00:00:00/01:00:00:00:00:00;OK +--src-mac=01:02:03:04:05:06 --dst-mac=07:08:09:0A:0B:0C --h-length=6 --opcode=Request --h-type=Ethernet --proto-type=ipv4;--src-mac 01:02:03:04:05:06 --dst-mac 07:08:09:0a:0b:0c --opcode 1 --proto-type 0x800;OK +--src-mac ! 01:02:03:04:05:06 --dst-mac ! 07:08:09:0A:0B:0C --h-length ! 6 --opcode ! Request --h-type ! Ethernet --proto-type ! ipv4;! --src-mac 01:02:03:04:05:06 ! --dst-mac 07:08:09:0a:0b:0c ! --h-length 6 ! --opcode 1 ! --h-type 1 ! --proto-type 0x800;OK diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t index 56d6da2e..6ed978e4 100644 --- a/extensions/libxt_standard.t +++ b/extensions/libxt_standard.t @@ -21,3 +21,6 @@ -s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK -s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK -s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK +:FORWARD +--protocol=tcp --source=1.2.3.4 --destination=5.6.7.8/32 --in-interface=eth0 --out-interface=eth1 --jump=ACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK +-ptcp -s1.2.3.4 -d5.6.7.8/32 -ieth0 -oeth1 -jACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK diff --git a/iptables/xshared.c b/iptables/xshared.c index ac51fac5..17aed04e 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1318,7 +1318,7 @@ static void check_empty_interface(struct xtables_args *args, const char *arg) } static void check_inverse(struct xtables_args *args, const char option[], - bool *invert, int *optidx, int argc) + bool *invert, int argc, char **argv) { switch (args->family) { case NFPROTO_ARP: @@ -1337,12 +1337,11 @@ static void check_inverse(struct xtables_args *args, const char option[], xtables_error(PARAMETER_PROBLEM, "Multiple `!' flags not allowed"); *invert = true; - if (optidx) { - *optidx = *optidx + 1; - if (argc && *optidx > argc) - xtables_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } + optind++; + if (optind > argc) + xtables_error(PARAMETER_PROBLEM, "no argument following `!'"); + + optarg = argv[optind - 1]; } static const char *optstring_lookup(int family) @@ -1555,16 +1554,16 @@ void do_parse(int argc, char *argv[], * Option selection */ case 'p': - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_PROTOCOL, &args->invflags, invert); /* Canonicalize into lower case */ - for (cs->protocol = argv[optind - 1]; + for (cs->protocol = optarg; *cs->protocol; cs->protocol++) *cs->protocol = tolower(*cs->protocol); - cs->protocol = argv[optind - 1]; + cs->protocol = optarg; args->proto = xtables_parse_protocol(cs->protocol); if (args->proto == 0 && @@ -1578,17 +1577,17 @@ void do_parse(int argc, char *argv[], break; case 's': - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_SOURCE, &args->invflags, invert); - args->shostnetworkmask = argv[optind - 1]; + args->shostnetworkmask = optarg; break; case 'd': - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_DESTINATION, &args->invflags, invert); - args->dhostnetworkmask = argv[optind - 1]; + args->dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO @@ -1601,71 +1600,71 @@ void do_parse(int argc, char *argv[], #endif case 2:/* src-mac */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_S_MAC, &args->invflags, invert); - args->src_mac = argv[optind - 1]; + args->src_mac = optarg; break; case 3:/* dst-mac */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_D_MAC, &args->invflags, invert); - args->dst_mac = argv[optind - 1]; + args->dst_mac = optarg; break; case 'l':/* hardware length */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_H_LENGTH, &args->invflags, invert); - args->arp_hlen = argv[optind - 1]; + args->arp_hlen = optarg; break; case 8: /* was never supported, not even in arptables-legacy */ xtables_error(PARAMETER_PROBLEM, "not supported"); case 4:/* opcode */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_OPCODE, &args->invflags, invert); - args->arp_opcode = argv[optind - 1]; + args->arp_opcode = optarg; break; case 5:/* h-type */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_H_TYPE, &args->invflags, invert); - args->arp_htype = argv[optind - 1]; + args->arp_htype = optarg; break; case 6:/* proto-type */ - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_P_TYPE, &args->invflags, invert); - args->arp_ptype = argv[optind - 1]; + args->arp_ptype = optarg; break; case 'j': set_option(&cs->options, OPT_JUMP, &args->invflags, invert); - command_jump(cs, argv[optind - 1]); + command_jump(cs, optarg); break; case 'i': check_empty_interface(args, optarg); - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_VIANAMEIN, &args->invflags, invert); - xtables_parse_interface(argv[optind - 1], + xtables_parse_interface(optarg, args->iniface, args->iniface_mask); break; case 'o': check_empty_interface(args, optarg); - check_inverse(args, optarg, &invert, &optind, argc); + check_inverse(args, optarg, &invert, argc, argv); set_option(&cs->options, OPT_VIANAMEOUT, &args->invflags, invert); - xtables_parse_interface(argv[optind - 1], + xtables_parse_interface(optarg, args->outiface, args->outiface_mask); break; -- cgit v1.2.3 From 46ed4d264ce44dd0a01723a1e326eedc0da822ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 29 Mar 2023 17:53:11 +0200 Subject: nft: Introduce nft-ruleparse.{c,h} Extract all code dealing with parsing from struct nftnl_rule into struct iptables_command_state from nft-shared.c into a separate source file. Basically this is nft_rule_to_iptables_command_state() and the functions it calls, plus family-independent parsers called from family-specific callbacks. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 1 + iptables/nft-ruleparse.c | 1208 ++++++++++++++++++++++++++++++++++++++++++++++ iptables/nft-ruleparse.h | 117 +++++ iptables/nft-shared.c | 1190 --------------------------------------------- iptables/nft-shared.h | 101 +--- 5 files changed, 1327 insertions(+), 1290 deletions(-) create mode 100644 iptables/nft-ruleparse.c create mode 100644 iptables/nft-ruleparse.h diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 1f37640f..d5922da6 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -46,6 +46,7 @@ xtables_nft_multi_SOURCES += nft.c nft.h \ nft-cache.c nft-cache.h \ nft-chain.c nft-chain.h \ nft-cmd.c nft-cmd.h \ + nft-ruleparse.c nft-ruleparse.h \ nft-shared.c nft-shared.h \ xtables-monitor.c \ xtables.c xtables-arp.c xtables-eb.c \ diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c new file mode 100644 index 00000000..2d84241a --- /dev/null +++ b/iptables/nft-ruleparse.c @@ -0,0 +1,1208 @@ +/* + * (C) 2012-2013 by Pablo Neira Ayuso + * (C) 2013 by Tomasz Bursztyka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "nft-ruleparse.h" +#include "nft.h" + +static struct xtables_match * +nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) +{ + struct xtables_rule_match *rm; + struct ebt_match *ebm; + + for (ebm = cs->match_list; ebm; ebm = ebm->next) { + if (ebm->ismatch && + !strcmp(ebm->u.match->m->u.user.name, name)) + return ebm->u.match; + } + for (rm = cs->matches; rm; rm = rm->next) { + if (!strcmp(rm->match->m->u.user.name, name)) + return rm->match; + } + return NULL; +} + +void * +nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name, bool reuse) +{ + struct xtables_match *match; + struct xt_entry_match *m; + unsigned int size; + + if (reuse) { + match = nft_find_match_in_cs(cs, name); + if (match) + return match->m->data; + } + + match = xtables_find_match(name, XTF_TRY_LOAD, + &cs->matches); + if (!match) + return NULL; + + size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; + m = xtables_calloc(1, size); + m->u.match_size = size; + m->u.user.revision = match->revision; + + strcpy(m->u.user.name, match->name); + match->m = m; + + xs_init_match(match); + + if (ctx->h->ops->parse_match) + ctx->h->ops->parse_match(match, cs); + + return match->m->data; +} + +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); +} + +static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum); + + if (!reg) + return; + + reg->type = NFT_XT_REG_PAYLOAD; + reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); + reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); + reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); +} + +static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, + struct nft_xt_ctx_reg *sreg) +{ + if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { + ctx->errmsg = "meta sreg is not an immediate"; + return false; + } + + if (sreg->immediate.data[0] == 0) { + ctx->errmsg = "meta sreg immediate is 0"; + return false; + } + + return true; +} + +static void nft_parse_meta_set(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) +{ + struct xtables_target *target; + struct nft_xt_ctx_reg *sreg; + enum nft_registers sregnum; + struct xt_entry_target *t; + unsigned int size; + const char *targname; + + sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + if (!sreg) + return; + + switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) { + case NFT_META_NFTRACE: + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + targname = "TRACE"; + break; + case NFT_META_BRI_BROUTE: + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + ctx->cs->jumpto = "DROP"; + return; + default: + ctx->errmsg = "meta sreg key not supported"; + return; + } + + target = xtables_find_target(targname, XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "target TRACE not found"; + return; + } + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; + + t = xtables_calloc(1, size); + t->u.target_size = size; + t->u.user.revision = target->revision; + strcpy(t->u.user.name, targname); + + target->t = t; + + ctx->h->ops->parse_target(target, ctx->cs); +} + +static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *reg; + + if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { + nft_parse_meta_set(ctx, e); + return; + } + + reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG)); + if (!reg) + return; + + reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); + reg->type = NFT_XT_REG_META_DREG; +} + +static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); + enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); + struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + struct nft_xt_ctx_reg *dreg = sreg; + const void *data; + uint32_t len; + + if (!sreg) + return; + + if (sregnum != dregnum) { + dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */ + if (!dreg) + return; + + *dreg = *sreg; /* .. and copy content instead */ + } + + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); + + if (len > sizeof(dreg->bitwise.xor)) { + ctx->errmsg = "bitwise xor too large"; + return; + } + + memcpy(dreg->bitwise.xor, data, len); + + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); + + if (len > sizeof(dreg->bitwise.mask)) { + ctx->errmsg = "bitwise mask too large"; + return; + } + + memcpy(dreg->bitwise.mask, data, len); + + dreg->bitwise.set = true; +} + +static void nft_parse_icmp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + struct nft_xt_ctx_reg *sreg, + uint8_t op, const char *data, size_t dlen) +{ + struct ipt_icmp icmp = { + .type = UINT8_MAX, + .code = { 0, UINT8_MAX }, + }, *icmpp; + + if (dlen < 1) + goto out_err_len; + + switch (sreg->payload.offset) { + case 0: + icmp.type = data[0]; + if (dlen == 1) + break; + dlen--; + data++; + /* fall through */ + case 1: + if (dlen > 1) + goto out_err_len; + icmp.code[0] = icmp.code[1] = data[0]; + break; + default: + ctx->errmsg = "unexpected payload offset"; + return; + } + + switch (ctx->h->family) { + case NFPROTO_IPV4: + icmpp = nft_create_match(ctx, cs, "icmp", false); + break; + case NFPROTO_IPV6: + if (icmp.type == UINT8_MAX) { + ctx->errmsg = "icmp6 code with any type match not supported"; + return; + } + icmpp = nft_create_match(ctx, cs, "icmp6", false); + break; + default: + ctx->errmsg = "unexpected family for icmp match"; + return; + } + + if (!icmpp) { + ctx->errmsg = "icmp match extension not found"; + return; + } + memcpy(icmpp, &icmp, sizeof(icmp)); + return; + +out_err_len: + ctx->errmsg = "unexpected RHS data length"; +} + +static void port_match_single_to_range(__u16 *ports, __u8 *invflags, + uint8_t op, int port, __u8 invflag) +{ + if (port < 0) + return; + + switch (op) { + case NFT_CMP_NEQ: + *invflags |= invflag; + /* fallthrough */ + case NFT_CMP_EQ: + ports[0] = port; + ports[1] = port; + break; + case NFT_CMP_LT: + ports[1] = max(port - 1, 1); + break; + case NFT_CMP_LTE: + ports[1] = port; + break; + case NFT_CMP_GT: + ports[0] = min(port + 1, UINT16_MAX); + break; + case NFT_CMP_GTE: + ports[0] = port; + break; + } +} + +static void nft_parse_udp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); + + if (!udp) { + ctx->errmsg = "udp match extension not found"; + return; + } + + port_match_single_to_range(udp->spts, &udp->invflags, + op, sport, XT_UDP_INV_SRCPT); + port_match_single_to_range(udp->dpts, &udp->invflags, + op, dport, XT_UDP_INV_DSTPT); +} + +static void nft_parse_tcp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + port_match_single_to_range(tcp->spts, &tcp->invflags, + op, sport, XT_TCP_INV_SRCPT); + port_match_single_to_range(tcp->dpts, &tcp->invflags, + op, dport, XT_TCP_INV_DSTPT); +} + +static void nft_parse_th_port(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport, int dport, uint8_t op) +{ + switch (proto) { + case IPPROTO_UDP: + nft_parse_udp(ctx, cs, sport, dport, op); + break; + case IPPROTO_TCP: + nft_parse_tcp(ctx, cs, sport, dport, op); + break; + default: + ctx->errmsg = "unknown layer 4 protocol for TH match"; + } +} + +static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t op, uint8_t flags, uint8_t mask) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + if (op == NFT_CMP_NEQ) + tcp->invflags |= XT_TCP_INV_FLAGS; + tcp->flg_cmp = flags; + tcp->flg_mask = mask; +} + +static void nft_parse_transport(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct nft_xt_ctx_reg *sreg; + enum nft_registers reg; + uint32_t sdport; + uint16_t port; + uint8_t proto, op; + unsigned int len; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + ctx->errmsg = "invalid family for TH match"; + return; + } + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) + return; + + if (sreg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "sgreg not payload"; + return; + } + + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + nft_parse_icmp(ctx, cs, sreg, op, + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), + len); + return; + default: + ctx->errmsg = "unsupported layer 4 protocol value"; + return; + } + + switch(sreg->payload.offset) { + case 0: /* th->sport */ + switch (len) { + case 2: /* load sport only */ + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, port, -1, op); + return; + case 4: /* load both src and dst port */ + sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op); + return; + } + break; + case 2: /* th->dport */ + switch (len) { + case 2: + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, -1, port, op); + return; + } + break; + case 13: /* th->flags */ + if (len == 1 && proto == IPPROTO_TCP) { + uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + uint8_t mask = ~0; + + if (sreg->bitwise.set) + memcpy(&mask, &sreg->bitwise.mask, sizeof(mask)); + + nft_parse_tcp_flags(ctx, cs, op, flags, mask); + } + return; + } +} + +static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); + + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) + return; + + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "cmp sreg undef"; + break; + case NFT_XT_REG_META_DREG: + ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs); + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { + case NFT_PAYLOAD_LL_HEADER: + if (ctx->h->family == NFPROTO_BRIDGE) + ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_NETWORK_HEADER: + ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport(ctx, e, ctx->cs); + break; + } + + break; + default: + ctx->errmsg = "cmp sreg has unknown type"; + break; + } +} + +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 iptables_command_state *cs = ctx->cs; + struct xt_entry_target *t; + uint32_t size; + int verdict; + + if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { + struct nft_xt_ctx_reg *dreg; + const void *imm_data; + uint32_t len; + + imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len); + dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); + if (!dreg) + return; + + if (len > sizeof(dreg->immediate.data)) { + ctx->errmsg = "oversized immediate data"; + return; + } + + memcpy(dreg->immediate.data, imm_data, len); + dreg->immediate.len = len; + dreg->type = NFT_XT_REG_IMMEDIATE; + + return; + } + + verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); + /* Standard target? */ + switch(verdict) { + case NF_ACCEPT: + if (cs->jumpto && strcmp(ctx->table, "broute") == 0) + break; + cs->jumpto = "ACCEPT"; + break; + case NF_DROP: + cs->jumpto = "DROP"; + break; + case NFT_RETURN: + cs->jumpto = "RETURN"; + break;; + case NFT_GOTO: + if (ctx->h->ops->set_goto_flag) + ctx->h->ops->set_goto_flag(cs); + /* fall through */ + case NFT_JUMP: + cs->jumpto = chain; + /* fall through */ + default: + return; + } + + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + if (!cs->target) { + ctx->errmsg = "verdict extension not found"; + 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; +} + +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); + const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); + struct xtables_match *match; + struct xtables_rule_match **matches; + struct xt_entry_match *m; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_BRIDGE: + matches = &ctx->cs->matches; + break; + default: + fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", + ctx->h->family); + exit(EXIT_FAILURE); + } + + match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); + if (match == NULL) { + ctx->errmsg = "match extension not found"; + return; + } + + m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); + memcpy(&m->data, mt_info, mt_len); + m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); + m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); + strcpy(m->u.user.name, match->name); + + match->m = m; + + if (ctx->h->ops->parse_match != NULL) + ctx->h->ops->parse_match(match, ctx->cs); +} + +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); + const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); + struct xtables_target *target; + struct xt_entry_target *t; + size_t size; + + target = xtables_find_target(targname, XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "target extension not found"; + return; + } + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; + + t = xtables_calloc(1, size); + memcpy(&t->data, targinfo, tg_len); + t->u.target_size = size; + t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); + strcpy(t->u.user.name, target->name); + + target->t = t; + + ctx->h->ops->parse_target(target, ctx->cs); +} + +static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); + __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); + __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); + struct xt_rateinfo *rinfo; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_BRIDGE: + break; + default: + fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", + ctx->h->family); + exit(EXIT_FAILURE); + } + + rinfo = nft_create_match(ctx, ctx->cs, "limit", false); + if (!rinfo) { + ctx->errmsg = "limit match extension not found"; + return; + } + + rinfo->avg = XT_LIMIT_SCALE * unit / rate; + rinfo->burst = burst; +} + +static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, + struct nftnl_expr *e) +{ + if (ctx->h->ops->parse_lookup) + ctx->h->ops->parse_lookup(ctx, e); +} + +static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xtables_target *target; + struct xt_entry_target *t; + size_t target_size; + /* + * In order to handle the longer log-prefix supported by nft, instead of + * using struct xt_nflog_info, we use a struct with a compatible layout, but + * a larger buffer for the prefix. + */ + struct xt_nflog_info_nft { + __u32 len; + __u16 group; + __u16 threshold; + __u16 flags; + __u16 pad; + char prefix[NF_LOG_PREFIXLEN]; + } info = { + .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), + .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), + }; + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { + info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); + info.flags = XT_NFLOG_F_COPY_LEN; + } + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX)) + snprintf(info.prefix, sizeof(info.prefix), "%s", + nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); + + target = xtables_find_target("NFLOG", XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "NFLOG target extension not found"; + return; + } + + target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + + XT_ALIGN(sizeof(struct xt_nflog_info_nft)); + + t = xtables_calloc(1, target_size); + t->u.target_size = target_size; + strcpy(t->u.user.name, target->name); + t->u.user.revision = target->revision; + + target->t = t; + + memcpy(&target->t->data, &info, sizeof(info)); + + ctx->h->ops->parse_target(target, ctx->cs); +} + +static void nft_parse_udp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); + + if (!udp) { + ctx->errmsg = "udp match extension not found"; + return; + } + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + udp->invflags |= XT_UDP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + udp->spts[0] = sport_from; + udp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + udp->invflags |= XT_UDP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + udp->dpts[0] = dport_from; + udp->dpts[1] = dport_to; + break; + } + } +} + +static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + tcp->invflags |= XT_TCP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + tcp->spts[0] = sport_from; + tcp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + tcp->invflags |= XT_TCP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + tcp->dpts[0] = dport_from; + tcp->dpts[1] = dport_to; + break; + } + } +} + +static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport_from, int sport_to, + int dport_from, int dport_to, uint8_t op) +{ + switch (proto) { + case IPPROTO_UDP: + nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + case IPPROTO_TCP: + nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + } +} + +static void nft_parse_transport_range(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + unsigned int len_from, len_to; + uint8_t proto, op; + uint16_t from, to; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + proto = 0; + break; + } + + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from); + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to); + if (len_to != len_from || len_to != 2) + return; + + op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP); + + from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + + switch (sreg->payload.offset) { + case 0: + nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); + return; + case 2: + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op); + return; + } +} + +static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, reg); + + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "range sreg undef"; + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport_range(ctx, sreg, e, ctx->cs); + break; + default: + ctx->errmsg = "range with unknown payload base"; + break; + } + break; + default: + ctx->errmsg = "range sreg type unsupported"; + break; + } +} + +bool nft_rule_to_iptables_command_state(struct nft_handle *h, + const struct nftnl_rule *r, + struct iptables_command_state *cs) +{ + struct nftnl_expr_iter *iter; + struct nftnl_expr *expr; + struct nft_xt_ctx ctx = { + .cs = cs, + .h = h, + .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), + }; + bool ret = true; + + iter = nftnl_expr_iter_create(r); + if (iter == NULL) + return false; + + 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->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, "match") == 0) + nft_parse_match(&ctx, expr); + else if (strcmp(name, "target") == 0) + nft_parse_target(&ctx, expr); + else if (strcmp(name, "limit") == 0) + nft_parse_limit(&ctx, expr); + else if (strcmp(name, "lookup") == 0) + nft_parse_lookup(&ctx, h, expr); + else if (strcmp(name, "log") == 0) + nft_parse_log(&ctx, expr); + else if (strcmp(name, "range") == 0) + nft_parse_range(&ctx, expr); + + if (ctx.errmsg) { + fprintf(stderr, "Error: %s\n", ctx.errmsg); + ctx.errmsg = NULL; + ret = false; + } + + expr = nftnl_expr_iter_next(iter); + } + + nftnl_expr_iter_destroy(iter); + + if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { + const void *data; + uint32_t len, size; + const char *comment; + + data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); + 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 false; + + 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->jumpto) + cs->jumpto = ""; + + if (!ret) + xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed"); + return ret; +} + +static void parse_ifname(const char *name, unsigned int len, + char *dst, unsigned char *mask) +{ + if (len == 0) + return; + + memcpy(dst, name, len); + if (name[len - 1] == '\0') { + if (mask) + memset(mask, 0xff, strlen(name) + 1); + return; + } + + if (len >= IFNAMSIZ) + return; + + /* wildcard */ + dst[len++] = '+'; + if (len >= IFNAMSIZ) + return; + dst[len++] = 0; + if (mask) + memset(mask, 0xff, len - 2); +} + +static void parse_invalid_iface(char *iface, unsigned char *mask, + uint8_t *invflags, uint8_t invbit) +{ + if (*invflags & invbit || strcmp(iface, "INVAL/D")) + return; + + /* nft's poor "! -o +" excuse */ + *invflags |= invbit; + iface[0] = '+'; + iface[1] = '\0'; + mask[0] = 0xff; + mask[1] = 0xff; + memset(mask + 2, 0, IFNAMSIZ - 2); +} + +static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) +{ + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg); + + if (reg->bitwise.set) + return reg->bitwise.mask[0]; + + return ~0u; +} + +static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_mark_mtinfo1 *mark; + uint32_t value; + + mark = nft_create_match(ctx, ctx->cs, "mark", false); + if (!mark) + return -1; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + mark->invert = 1; + + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + mark->mark = value; + mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG)); + + return 0; +} + +static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_pkttype_info *pkttype; + uint8_t value; + + pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false); + if (!pkttype) + return -1; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + pkttype->invert = 1; + + value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + pkttype->pkttype = value; + + return 0; +} + +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, + char *outiface, unsigned char *outiface_mask, uint8_t *invflags) +{ + uint32_t value; + const void *ifname; + uint32_t len; + + switch(key) { + case NFT_META_IIF: + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_IN; + + if_indextoname(value, iniface); + + memset(iniface_mask, 0xff, strlen(iniface)+1); + break; + case NFT_META_OIF: + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_OUT; + + if_indextoname(value, outiface); + + memset(outiface_mask, 0xff, strlen(outiface)+1); + break; + case NFT_META_BRI_IIFNAME: + case NFT_META_IIFNAME: + ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_IN; + + parse_ifname(ifname, len, iniface, iniface_mask); + parse_invalid_iface(iniface, iniface_mask, + invflags, IPT_INV_VIA_IN); + break; + case NFT_META_BRI_OIFNAME: + case NFT_META_OIFNAME: + ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_OUT; + + parse_ifname(ifname, len, outiface, outiface_mask); + parse_invalid_iface(outiface, outiface_mask, + invflags, IPT_INV_VIA_OUT); + break; + case NFT_META_MARK: + parse_meta_mark(ctx, e); + break; + case NFT_META_PKTTYPE: + parse_meta_pkttype(ctx, e); + break; + default: + return -1; + } + + return 0; +} + +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) +{ + cs->target = t; + cs->jumpto = t->name; +} + +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ip6t_hl_info *info; + uint8_t hl, mode; + int op; + + hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + switch (op) { + case NFT_CMP_NEQ: + mode = IP6T_HL_NE; + break; + case NFT_CMP_EQ: + mode = IP6T_HL_EQ; + break; + case NFT_CMP_LT: + mode = IP6T_HL_LT; + break; + case NFT_CMP_GT: + mode = IP6T_HL_GT; + break; + case NFT_CMP_LTE: + mode = IP6T_HL_LT; + if (hl == 255) + return -1; + hl++; + break; + case NFT_CMP_GTE: + mode = IP6T_HL_GT; + if (hl == 0) + return -1; + hl--; + break; + default: + return -1; + } + + /* ipt_ttl_info and ip6t_hl_info have same layout, + * IPT_TTL_x and IP6T_HL_x are aliases as well, so + * just use HL for both ipv4 and ipv6. + */ + switch (ctx->h->family) { + case NFPROTO_IPV4: + info = nft_create_match(ctx, ctx->cs, "ttl", false); + break; + case NFPROTO_IPV6: + info = nft_create_match(ctx, ctx->cs, "hl", false); + break; + default: + return -1; + } + + if (!info) + return -1; + + info->hop_limit = hl; + info->mode = mode; + + return 0; +} diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h new file mode 100644 index 00000000..7fac6c79 --- /dev/null +++ b/iptables/nft-ruleparse.h @@ -0,0 +1,117 @@ +#ifndef _NFT_RULEPARSE_H_ +#define _NFT_RULEPARSE_H_ + +#include + +#include + +#include "xshared.h" + +enum nft_ctx_reg_type { + NFT_XT_REG_UNDEF, + NFT_XT_REG_PAYLOAD, + NFT_XT_REG_IMMEDIATE, + NFT_XT_REG_META_DREG, +}; + +struct nft_xt_ctx_reg { + enum nft_ctx_reg_type type:8; + + union { + struct { + uint32_t base; + uint32_t offset; + uint32_t len; + } payload; + struct { + uint32_t data[4]; + uint8_t len; + } immediate; + struct { + uint32_t key; + } meta_dreg; + struct { + uint32_t key; + } meta_sreg; + }; + + struct { + uint32_t mask[4]; + uint32_t xor[4]; + bool set; + } bitwise; +}; + +struct nft_xt_ctx { + struct iptables_command_state *cs; + struct nftnl_expr_iter *iter; + struct nft_handle *h; + uint32_t flags; + const char *table; + + struct nft_xt_ctx_reg regs[1 + 16]; + + const char *errmsg; +}; + +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + switch (reg) { + case NFT_REG_VERDICT: + return &ctx->regs[0]; + case NFT_REG_1: + return &ctx->regs[1]; + case NFT_REG_2: + return &ctx->regs[5]; + case NFT_REG_3: + return &ctx->regs[9]; + case NFT_REG_4: + return &ctx->regs[13]; + case NFT_REG32_00...NFT_REG32_15: + return &ctx->regs[reg - NFT_REG32_00]; + default: + ctx->errmsg = "Unknown register requested"; + break; + } + + return NULL; +} + +static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) +{ + r->type = 0; + r->bitwise.set = false; +} + +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg); + + if (r) + nft_xt_reg_clear(r); + + return r; +} + +void *nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name, bool reuse); + +bool nft_rule_to_iptables_command_state(struct nft_handle *h, + const struct nftnl_rule *r, + struct iptables_command_state *cs); + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, char *outiface, + unsigned char *outiface_mask, uint8_t *invflags); + +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs); + +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + struct iptables_command_state *cs); + +#endif /* _NFT_RULEPARSE_H_ */ diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 79f6a7d3..12860fbf 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -21,14 +21,6 @@ #include -#include -#include -#include -#include -#include - -#include - #include #include #include @@ -276,224 +268,6 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, return true; } -static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned char *mask) -{ - if (len == 0) - return; - - memcpy(dst, name, len); - if (name[len - 1] == '\0') { - if (mask) - memset(mask, 0xff, strlen(name) + 1); - return; - } - - if (len >= IFNAMSIZ) - return; - - /* wildcard */ - dst[len++] = '+'; - if (len >= IFNAMSIZ) - return; - dst[len++] = 0; - if (mask) - memset(mask, 0xff, len - 2); -} - -static void * -nft_create_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - const char *name, bool reuse); - -static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) -{ - struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg); - - if (reg->bitwise.set) - return reg->bitwise.mask[0]; - - return ~0u; -} - -static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct xt_mark_mtinfo1 *mark; - uint32_t value; - - mark = nft_create_match(ctx, ctx->cs, "mark", false); - if (!mark) - return -1; - - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - mark->invert = 1; - - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - mark->mark = value; - mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG)); - - return 0; -} - -static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct xt_pkttype_info *pkttype; - uint8_t value; - - pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false); - if (!pkttype) - return -1; - - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - pkttype->invert = 1; - - value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - pkttype->pkttype = value; - - return 0; -} - -static void parse_invalid_iface(char *iface, unsigned char *mask, - uint8_t *invflags, uint8_t invbit) -{ - if (*invflags & invbit || strcmp(iface, "INVAL/D")) - return; - - /* nft's poor "! -o +" excuse */ - *invflags |= invbit; - iface[0] = '+'; - iface[1] = '\0'; - mask[0] = 0xff; - mask[1] = 0xff; - memset(mask + 2, 0, IFNAMSIZ - 2); -} - -int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, - char *iniface, unsigned char *iniface_mask, - char *outiface, unsigned char *outiface_mask, uint8_t *invflags) -{ - uint32_t value; - const void *ifname; - uint32_t len; - - switch(key) { - case NFT_META_IIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - if_indextoname(value, iniface); - - memset(iniface_mask, 0xff, strlen(iniface)+1); - break; - case NFT_META_OIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - if_indextoname(value, outiface); - - memset(outiface_mask, 0xff, strlen(outiface)+1); - break; - case NFT_META_BRI_IIFNAME: - case NFT_META_IIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - parse_ifname(ifname, len, iniface, iniface_mask); - parse_invalid_iface(iniface, iniface_mask, - invflags, IPT_INV_VIA_IN); - break; - case NFT_META_BRI_OIFNAME: - case NFT_META_OIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - parse_ifname(ifname, len, outiface, outiface_mask); - parse_invalid_iface(outiface, outiface_mask, - invflags, IPT_INV_VIA_OUT); - break; - case NFT_META_MARK: - parse_meta_mark(ctx, e); - break; - case NFT_META_PKTTYPE: - parse_meta_pkttype(ctx, e); - break; - default: - return -1; - } - - return 0; -} - -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); - const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); - struct xtables_target *target; - struct xt_entry_target *t; - size_t size; - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) { - ctx->errmsg = "target extension not found"; - return; - } - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; - - t = xtables_calloc(1, size); - memcpy(&t->data, targinfo, tg_len); - t->u.target_size = size; - t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(t->u.user.name, target->name); - - target->t = t; - - ctx->h->ops->parse_target(target, ctx->cs); -} - -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); - const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); - struct xtables_match *match; - struct xtables_rule_match **matches; - struct xt_entry_match *m; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; - break; - default: - fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); - if (match == NULL) { - ctx->errmsg = "match extension not found"; - return; - } - - m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); - memcpy(&m->data, mt_info, mt_len); - m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); - m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(m->u.user.name, match->name); - - match->m = m; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); -} - void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op) { uint32_t len; @@ -510,899 +284,6 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) *inv = (op == NFT_CMP_NEQ); } -static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, - struct nft_xt_ctx_reg *sreg) -{ - if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { - ctx->errmsg = "meta sreg is not an immediate"; - return false; - } - - if (sreg->immediate.data[0] == 0) { - ctx->errmsg = "meta sreg immediate is 0"; - return false; - } - - return true; -} - -static void nft_parse_meta_set(struct nft_xt_ctx *ctx, - struct nftnl_expr *e) -{ - struct xtables_target *target; - struct nft_xt_ctx_reg *sreg; - enum nft_registers sregnum; - struct xt_entry_target *t; - unsigned int size; - const char *targname; - - sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); - sreg = nft_xt_ctx_get_sreg(ctx, sregnum); - if (!sreg) - return; - - switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) { - case NFT_META_NFTRACE: - if (!nft_parse_meta_set_common(ctx, sreg)) - return; - - targname = "TRACE"; - break; - case NFT_META_BRI_BROUTE: - if (!nft_parse_meta_set_common(ctx, sreg)) - return; - - ctx->cs->jumpto = "DROP"; - return; - default: - ctx->errmsg = "meta sreg key not supported"; - return; - } - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) { - ctx->errmsg = "target TRACE not found"; - return; - } - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = target->revision; - strcpy(t->u.user.name, targname); - - target->t = t; - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct nft_xt_ctx_reg *reg; - - if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { - nft_parse_meta_set(ctx, e); - return; - } - - reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG)); - if (!reg) - return; - - reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); - reg->type = NFT_XT_REG_META_DREG; -} - -static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); - struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum); - - if (!reg) - return; - - reg->type = NFT_XT_REG_PAYLOAD; - reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); - reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); - reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); -} - -static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); - enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); - struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum); - struct nft_xt_ctx_reg *dreg = sreg; - const void *data; - uint32_t len; - - if (!sreg) - return; - - if (sregnum != dregnum) { - dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */ - if (!dreg) - return; - - *dreg = *sreg; /* .. and copy content instead */ - } - - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); - - if (len > sizeof(dreg->bitwise.xor)) { - ctx->errmsg = "bitwise xor too large"; - return; - } - - memcpy(dreg->bitwise.xor, data, len); - - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); - - if (len > sizeof(dreg->bitwise.mask)) { - ctx->errmsg = "bitwise mask too large"; - return; - } - - memcpy(dreg->bitwise.mask, data, len); - - dreg->bitwise.set = true; -} - -static struct xtables_match * -nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) -{ - struct xtables_rule_match *rm; - struct ebt_match *ebm; - - for (ebm = cs->match_list; ebm; ebm = ebm->next) { - if (ebm->ismatch && - !strcmp(ebm->u.match->m->u.user.name, name)) - return ebm->u.match; - } - for (rm = cs->matches; rm; rm = rm->next) { - if (!strcmp(rm->match->m->u.user.name, name)) - return rm->match; - } - return NULL; -} - -static void * -nft_create_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - const char *name, bool reuse) -{ - struct xtables_match *match; - struct xt_entry_match *m; - unsigned int size; - - if (reuse) { - match = nft_find_match_in_cs(cs, name); - if (match) - return match->m->data; - } - - match = xtables_find_match(name, XTF_TRY_LOAD, - &cs->matches); - if (!match) - return NULL; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; - m = xtables_calloc(1, size); - m->u.match_size = size; - m->u.user.revision = match->revision; - - strcpy(m->u.user.name, match->name); - match->m = m; - - xs_init_match(match); - - if (ctx->h->ops->parse_match) - ctx->h->ops->parse_match(match, cs); - - return match->m->data; -} - -static void nft_parse_udp_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport_from, int sport_to, - int dport_from, int dport_to, - uint8_t op) -{ - struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); - - if (!udp) { - ctx->errmsg = "udp match extension not found"; - return; - } - - if (sport_from >= 0) { - switch (op) { - case NFT_RANGE_NEQ: - udp->invflags |= XT_UDP_INV_SRCPT; - /* fallthrough */ - case NFT_RANGE_EQ: - udp->spts[0] = sport_from; - udp->spts[1] = sport_to; - break; - } - } - - if (dport_to >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->dpts[0] = dport_from; - udp->dpts[1] = dport_to; - break; - } - } -} - -static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport_from, int sport_to, - int dport_from, int dport_to, - uint8_t op) -{ - struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - - if (!tcp) { - ctx->errmsg = "tcp match extension not found"; - return; - } - - if (sport_from >= 0) { - switch (op) { - case NFT_RANGE_NEQ: - tcp->invflags |= XT_TCP_INV_SRCPT; - /* fallthrough */ - case NFT_RANGE_EQ: - tcp->spts[0] = sport_from; - tcp->spts[1] = sport_to; - break; - } - } - - if (dport_to >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->dpts[0] = dport_from; - tcp->dpts[1] = dport_to; - break; - } - } -} - -static void port_match_single_to_range(__u16 *ports, __u8 *invflags, - uint8_t op, int port, __u8 invflag) -{ - if (port < 0) - return; - - switch (op) { - case NFT_CMP_NEQ: - *invflags |= invflag; - /* fallthrough */ - case NFT_CMP_EQ: - ports[0] = port; - ports[1] = port; - break; - case NFT_CMP_LT: - ports[1] = max(port - 1, 1); - break; - case NFT_CMP_LTE: - ports[1] = port; - break; - case NFT_CMP_GT: - ports[0] = min(port + 1, UINT16_MAX); - break; - case NFT_CMP_GTE: - ports[0] = port; - break; - } -} - -static void nft_parse_udp(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport, int dport, - uint8_t op) -{ - struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); - - if (!udp) { - ctx->errmsg = "udp match extension not found"; - return; - } - - port_match_single_to_range(udp->spts, &udp->invflags, - op, sport, XT_UDP_INV_SRCPT); - port_match_single_to_range(udp->dpts, &udp->invflags, - op, dport, XT_UDP_INV_DSTPT); -} - -static void nft_parse_tcp(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport, int dport, - uint8_t op) -{ - struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - - if (!tcp) { - ctx->errmsg = "tcp match extension not found"; - return; - } - - port_match_single_to_range(tcp->spts, &tcp->invflags, - op, sport, XT_TCP_INV_SRCPT); - port_match_single_to_range(tcp->dpts, &tcp->invflags, - op, dport, XT_TCP_INV_DSTPT); -} - -static void nft_parse_icmp(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - struct nft_xt_ctx_reg *sreg, - uint8_t op, const char *data, size_t dlen) -{ - struct ipt_icmp icmp = { - .type = UINT8_MAX, - .code = { 0, UINT8_MAX }, - }, *icmpp; - - if (dlen < 1) - goto out_err_len; - - switch (sreg->payload.offset) { - case 0: - icmp.type = data[0]; - if (dlen == 1) - break; - dlen--; - data++; - /* fall through */ - case 1: - if (dlen > 1) - goto out_err_len; - icmp.code[0] = icmp.code[1] = data[0]; - break; - default: - ctx->errmsg = "unexpected payload offset"; - return; - } - - switch (ctx->h->family) { - case NFPROTO_IPV4: - icmpp = nft_create_match(ctx, cs, "icmp", false); - break; - case NFPROTO_IPV6: - if (icmp.type == UINT8_MAX) { - ctx->errmsg = "icmp6 code with any type match not supported"; - return; - } - icmpp = nft_create_match(ctx, cs, "icmp6", false); - break; - default: - ctx->errmsg = "unexpected family for icmp match"; - return; - } - - if (!icmpp) { - ctx->errmsg = "icmp match extension not found"; - return; - } - memcpy(icmpp, &icmp, sizeof(icmp)); - return; - -out_err_len: - ctx->errmsg = "unexpected RHS data length"; -} - -static void nft_parse_th_port(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t proto, - int sport, int dport, uint8_t op) -{ - switch (proto) { - case IPPROTO_UDP: - nft_parse_udp(ctx, cs, sport, dport, op); - break; - case IPPROTO_TCP: - nft_parse_tcp(ctx, cs, sport, dport, op); - break; - default: - ctx->errmsg = "unknown layer 4 protocol for TH match"; - } -} - -static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t proto, - int sport_from, int sport_to, - int dport_from, int dport_to, uint8_t op) -{ - switch (proto) { - case IPPROTO_UDP: - nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); - break; - case IPPROTO_TCP: - nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); - break; - } -} - -static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t op, uint8_t flags, uint8_t mask) -{ - struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); - - if (!tcp) { - ctx->errmsg = "tcp match extension not found"; - return; - } - - if (op == NFT_CMP_NEQ) - tcp->invflags |= XT_TCP_INV_FLAGS; - tcp->flg_cmp = flags; - tcp->flg_mask = mask; -} - -static void nft_parse_transport(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct nft_xt_ctx_reg *sreg; - enum nft_registers reg; - uint32_t sdport; - uint16_t port; - uint8_t proto, op; - unsigned int len; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - proto = ctx->cs->fw.ip.proto; - break; - case NFPROTO_IPV6: - proto = ctx->cs->fw6.ipv6.proto; - break; - default: - ctx->errmsg = "invalid family for TH match"; - return; - } - - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); - sreg = nft_xt_ctx_get_sreg(ctx, reg); - if (!sreg) - return; - - if (sreg->type != NFT_XT_REG_PAYLOAD) { - ctx->errmsg = "sgreg not payload"; - return; - } - - switch (proto) { - case IPPROTO_UDP: - case IPPROTO_TCP: - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - nft_parse_icmp(ctx, cs, sreg, op, - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), - len); - return; - default: - ctx->errmsg = "unsupported layer 4 protocol value"; - return; - } - - switch(sreg->payload.offset) { - case 0: /* th->sport */ - switch (len) { - case 2: /* load sport only */ - port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, port, -1, op); - return; - case 4: /* load both src and dst port */ - sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op); - return; - } - break; - case 2: /* th->dport */ - switch (len) { - case 2: - port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, -1, port, op); - return; - } - break; - case 13: /* th->flags */ - if (len == 1 && proto == IPPROTO_TCP) { - uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - uint8_t mask = ~0; - - if (sreg->bitwise.set) - memcpy(&mask, &sreg->bitwise.mask, sizeof(mask)); - - nft_parse_tcp_flags(ctx, cs, op, flags, mask); - } - return; - } -} - -static void nft_parse_transport_range(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *sreg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - unsigned int len_from, len_to; - uint8_t proto, op; - uint16_t from, to; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - proto = ctx->cs->fw.ip.proto; - break; - case NFPROTO_IPV6: - proto = ctx->cs->fw6.ipv6.proto; - break; - default: - proto = 0; - break; - } - - nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from); - nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to); - if (len_to != len_from || len_to != 2) - return; - - op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP); - - from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); - to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); - - switch (sreg->payload.offset) { - case 0: - nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); - return; - case 2: - to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); - nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op); - return; - } -} - -static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct nft_xt_ctx_reg *sreg; - uint32_t reg; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); - - sreg = nft_xt_ctx_get_sreg(ctx, reg); - if (!sreg) - return; - - switch (sreg->type) { - case NFT_XT_REG_UNDEF: - ctx->errmsg = "cmp sreg undef"; - break; - case NFT_XT_REG_META_DREG: - ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs); - break; - case NFT_XT_REG_PAYLOAD: - switch (sreg->payload.base) { - case NFT_PAYLOAD_LL_HEADER: - if (ctx->h->family == NFPROTO_BRIDGE) - ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); - break; - case NFT_PAYLOAD_NETWORK_HEADER: - ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); - break; - case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport(ctx, e, ctx->cs); - break; - } - - break; - default: - ctx->errmsg = "cmp sreg has unknown type"; - break; - } -} - -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); -} - -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 iptables_command_state *cs = ctx->cs; - struct xt_entry_target *t; - uint32_t size; - int verdict; - - if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { - struct nft_xt_ctx_reg *dreg; - const void *imm_data; - uint32_t len; - - imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len); - dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); - if (!dreg) - return; - - if (len > sizeof(dreg->immediate.data)) { - ctx->errmsg = "oversized immediate data"; - return; - } - - memcpy(dreg->immediate.data, imm_data, len); - dreg->immediate.len = len; - dreg->type = NFT_XT_REG_IMMEDIATE; - - return; - } - - verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); - /* Standard target? */ - switch(verdict) { - case NF_ACCEPT: - if (cs->jumpto && strcmp(ctx->table, "broute") == 0) - break; - cs->jumpto = "ACCEPT"; - break; - case NF_DROP: - cs->jumpto = "DROP"; - break; - case NFT_RETURN: - cs->jumpto = "RETURN"; - break;; - case NFT_GOTO: - if (ctx->h->ops->set_goto_flag) - ctx->h->ops->set_goto_flag(cs); - /* fall through */ - case NFT_JUMP: - cs->jumpto = chain; - /* fall through */ - default: - return; - } - - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - if (!cs->target) { - ctx->errmsg = "verdict extension not found"; - 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; -} - -static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); - __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); - __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); - struct xt_rateinfo *rinfo; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - break; - default: - fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - rinfo = nft_create_match(ctx, ctx->cs, "limit", false); - if (!rinfo) { - ctx->errmsg = "limit match extension not found"; - return; - } - - rinfo->avg = XT_LIMIT_SCALE * unit / rate; - rinfo->burst = burst; -} - -static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct xtables_target *target; - struct xt_entry_target *t; - size_t target_size; - /* - * In order to handle the longer log-prefix supported by nft, instead of - * using struct xt_nflog_info, we use a struct with a compatible layout, but - * a larger buffer for the prefix. - */ - struct xt_nflog_info_nft { - __u32 len; - __u16 group; - __u16 threshold; - __u16 flags; - __u16 pad; - char prefix[NF_LOG_PREFIXLEN]; - } info = { - .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), - .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), - }; - if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { - info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); - info.flags = XT_NFLOG_F_COPY_LEN; - } - if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX)) - snprintf(info.prefix, sizeof(info.prefix), "%s", - nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); - - target = xtables_find_target("NFLOG", XTF_TRY_LOAD); - if (target == NULL) { - ctx->errmsg = "NFLOG target extension not found"; - return; - } - - target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + - XT_ALIGN(sizeof(struct xt_nflog_info_nft)); - - t = xtables_calloc(1, target_size); - t->u.target_size = target_size; - strcpy(t->u.user.name, target->name); - t->u.user.revision = target->revision; - - target->t = t; - - memcpy(&target->t->data, &info, sizeof(info)); - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, - struct nftnl_expr *e) -{ - if (ctx->h->ops->parse_lookup) - ctx->h->ops->parse_lookup(ctx, e); -} - -static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct nft_xt_ctx_reg *sreg; - uint32_t reg; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); - sreg = nft_xt_ctx_get_sreg(ctx, reg); - - switch (sreg->type) { - case NFT_XT_REG_UNDEF: - ctx->errmsg = "range sreg undef"; - break; - case NFT_XT_REG_PAYLOAD: - switch (sreg->payload.base) { - case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport_range(ctx, sreg, e, ctx->cs); - break; - default: - ctx->errmsg = "range with unknown payload base"; - break; - } - break; - default: - ctx->errmsg = "range sreg type unsupported"; - break; - } -} - -bool nft_rule_to_iptables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs) -{ - struct nftnl_expr_iter *iter; - struct nftnl_expr *expr; - struct nft_xt_ctx ctx = { - .cs = cs, - .h = h, - .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), - }; - bool ret = true; - - iter = nftnl_expr_iter_create(r); - if (iter == NULL) - return false; - - 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->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, "match") == 0) - nft_parse_match(&ctx, expr); - else if (strcmp(name, "target") == 0) - nft_parse_target(&ctx, expr); - else if (strcmp(name, "limit") == 0) - nft_parse_limit(&ctx, expr); - else if (strcmp(name, "lookup") == 0) - nft_parse_lookup(&ctx, h, expr); - else if (strcmp(name, "log") == 0) - nft_parse_log(&ctx, expr); - else if (strcmp(name, "range") == 0) - nft_parse_range(&ctx, expr); - - if (ctx.errmsg) { - fprintf(stderr, "Error: %s\n", ctx.errmsg); - ctx.errmsg = NULL; - ret = false; - } - - expr = nftnl_expr_iter_next(iter); - } - - nftnl_expr_iter_destroy(iter); - - if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { - const void *data; - uint32_t len, size; - const char *comment; - - data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); - 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 false; - - 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->jumpto) - cs->jumpto = ""; - - if (!ret) - xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed"); - return ret; -} - void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) { const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); @@ -1546,13 +427,6 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2) return true; } -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - cs->target = t; - cs->jumpto = t->name; -} - void nft_check_xt_legacy(int family, bool is_ipt_save) { static const char tables6[] = "/proc/net/ip6_tables_names"; @@ -1587,70 +461,6 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) fclose(fp); } -int nft_parse_hl(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ip6t_hl_info *info; - uint8_t hl, mode; - int op; - - hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - - switch (op) { - case NFT_CMP_NEQ: - mode = IP6T_HL_NE; - break; - case NFT_CMP_EQ: - mode = IP6T_HL_EQ; - break; - case NFT_CMP_LT: - mode = IP6T_HL_LT; - break; - case NFT_CMP_GT: - mode = IP6T_HL_GT; - break; - case NFT_CMP_LTE: - mode = IP6T_HL_LT; - if (hl == 255) - return -1; - hl++; - break; - case NFT_CMP_GTE: - mode = IP6T_HL_GT; - if (hl == 0) - return -1; - hl--; - break; - default: - return -1; - } - - /* ipt_ttl_info and ip6t_hl_info have same layout, - * IPT_TTL_x and IP6T_HL_x are aliases as well, so - * just use HL for both ipv4 and ipv6. - */ - switch (ctx->h->family) { - case NFPROTO_IPV4: - info = nft_create_match(ctx, ctx->cs, "ttl", false); - break; - case NFPROTO_IPV6: - info = nft_create_match(ctx, ctx->cs, "hl", false); - break; - default: - return -1; - } - - if (!info) - return -1; - - info->hop_limit = hl; - info->mode = mode; - - return 0; -} - enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size) { /* convert size to NETLINK_ALIGN-sized chunks */ diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 2c4c0d90..2edee649 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -11,6 +11,7 @@ #include #include "xshared.h" +#include "nft-ruleparse.h" #ifdef DEBUG #define DEBUG_DEL @@ -38,92 +39,6 @@ struct xtables_args; struct nft_handle; struct xt_xlate; -enum nft_ctx_reg_type { - NFT_XT_REG_UNDEF, - NFT_XT_REG_PAYLOAD, - NFT_XT_REG_IMMEDIATE, - NFT_XT_REG_META_DREG, -}; - -struct nft_xt_ctx_reg { - enum nft_ctx_reg_type type:8; - - union { - struct { - uint32_t base; - uint32_t offset; - uint32_t len; - } payload; - struct { - uint32_t data[4]; - uint8_t len; - } immediate; - struct { - uint32_t key; - } meta_dreg; - struct { - uint32_t key; - } meta_sreg; - }; - - struct { - uint32_t mask[4]; - uint32_t xor[4]; - bool set; - } bitwise; -}; - -struct nft_xt_ctx { - struct iptables_command_state *cs; - struct nftnl_expr_iter *iter; - struct nft_handle *h; - uint32_t flags; - const char *table; - - struct nft_xt_ctx_reg regs[1 + 16]; - - const char *errmsg; -}; - -static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg) -{ - switch (reg) { - case NFT_REG_VERDICT: - return &ctx->regs[0]; - case NFT_REG_1: - return &ctx->regs[1]; - case NFT_REG_2: - return &ctx->regs[5]; - case NFT_REG_3: - return &ctx->regs[9]; - case NFT_REG_4: - return &ctx->regs[13]; - case NFT_REG32_00...NFT_REG32_15: - return &ctx->regs[reg - NFT_REG32_00]; - default: - ctx->errmsg = "Unknown register requested"; - break; - } - - return NULL; -} - -static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) -{ - r->type = 0; - r->bitwise.set = false; -} - -static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) -{ - struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg); - - if (r) - nft_xt_reg_clear(r); - - return r; -} - struct nft_family_ops { int (*add)(struct nft_handle *h, struct nftnl_rule *r, struct iptables_command_state *cs); @@ -207,14 +122,8 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, unsigned const char *b_iniface_mask, unsigned const char *b_outiface_mask); -int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, - char *iniface, unsigned char *iniface_mask, char *outiface, - unsigned char *outiface_mask, uint8_t *invflags); void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); -bool nft_rule_to_iptables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); @@ -224,9 +133,6 @@ void save_matches_and_target(const struct iptables_command_state *cs, struct nft_family_ops *nft_family_ops_lookup(int family); -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs); - bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); @@ -263,11 +169,6 @@ void xtables_restore_parse(struct nft_handle *h, void nft_check_xt_legacy(int family, bool is_ipt_save); -int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs); - -#define min(x, y) ((x) < (y) ? (x) : (y)) -#define max(x, y) ((x) > (y) ? (x) : (y)) - /* simplified nftables:include/netlink.h, netlink_padded_len() */ #define NETLINK_ALIGN 4 -- cgit v1.2.3 From 674e7c0f639f2322dcc7eee67aa9c3d52fa3ee65 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 29 Mar 2023 18:26:23 +0200 Subject: nft: Extract rule parsing callbacks from nft_family_ops Introduce struct nft_ruleparse_ops holding the family-specific expression parsers and integrate it into nft_family_ops for now. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 9 ++++++--- iptables/nft-bridge.c | 18 +++++++++++------- iptables/nft-ipv4.c | 10 +++++++--- iptables/nft-ipv6.c | 10 +++++++--- iptables/nft-ruleparse.c | 24 ++++++++++++------------ iptables/nft-ruleparse.h | 16 ++++++++++++++++ iptables/nft-shared.h | 14 +------------- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 3236e2f5..d2756309 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -781,23 +781,26 @@ nft_arp_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } +static struct nft_ruleparse_ops nft_ruleparse_ops_arp = { + .meta = nft_arp_parse_meta, + .payload = nft_arp_parse_payload, + .target = nft_ipv46_parse_target, +}; struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, .print_payload = NULL, - .parse_meta = nft_arp_parse_meta, - .parse_payload = nft_arp_parse_payload, .print_header = nft_arp_print_header, .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, + .rule_parse = &nft_ruleparse_ops_arp, .cmd_parse = { .post_parse = nft_arp_post_parse, }, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, .clear_cs = xtables_clear_iptables_command_state, - .parse_target = nft_ipv46_parse_target, .add_entry = nft_arp_add_entry, .delete_entry = nft_arp_delete_entry, .check_entry = nft_arp_check_entry, diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 22860d6b..0c9e1238 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -560,8 +560,8 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, match->m->u.user.revision = match->revision; xs_init_match(match); - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); + if (ctx->h->ops->rule_parse->match != NULL) + ctx->h->ops->rule_parse->match(match, ctx->cs); } if (!match) return; @@ -984,15 +984,19 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, return ret; } +static struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { + .meta = nft_bridge_parse_meta, + .payload = nft_bridge_parse_payload, + .lookup = nft_bridge_parse_lookup, + .match = nft_bridge_parse_match, + .target = nft_bridge_parse_target, +}; + struct nft_family_ops nft_family_ops_bridge = { .add = nft_bridge_add, .is_same = nft_bridge_is_same, .print_payload = NULL, - .parse_meta = nft_bridge_parse_meta, - .parse_payload = nft_bridge_parse_payload, - .parse_lookup = nft_bridge_parse_lookup, - .parse_match = nft_bridge_parse_match, - .parse_target = nft_bridge_parse_target, + .rule_parse = &nft_ruleparse_ops_bridge, .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, .print_rule = nft_bridge_print_rule, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index fadadd2e..3f769e88 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -440,21 +440,25 @@ nft_ipv4_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } +static struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = { + .meta = nft_ipv4_parse_meta, + .payload = nft_ipv4_parse_payload, + .target = nft_ipv46_parse_target, +}; + struct nft_family_ops nft_family_ops_ipv4 = { .add = nft_ipv4_add, .is_same = nft_ipv4_is_same, - .parse_meta = nft_ipv4_parse_meta, - .parse_payload = nft_ipv4_parse_payload, .set_goto_flag = nft_ipv4_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv4_print_rule, .save_rule = nft_ipv4_save_rule, .save_chain = nft_ipv46_save_chain, + .rule_parse = &nft_ruleparse_ops_ipv4, .cmd_parse = { .proto_parse = ipv4_proto_parse, .post_parse = ipv4_post_parse, }, - .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv4_xlate, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 85bb683f..962aaf0d 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -409,21 +409,25 @@ nft_ipv6_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } +static struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = { + .meta = nft_ipv6_parse_meta, + .payload = nft_ipv6_parse_payload, + .target = nft_ipv46_parse_target, +}; + struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, - .parse_meta = nft_ipv6_parse_meta, - .parse_payload = nft_ipv6_parse_payload, .set_goto_flag = nft_ipv6_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv6_print_rule, .save_rule = nft_ipv6_save_rule, .save_chain = nft_ipv46_save_chain, + .rule_parse = &nft_ruleparse_ops_ipv6, .cmd_parse = { .proto_parse = ipv6_proto_parse, .post_parse = ipv6_post_parse, }, - .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv6_xlate, diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c index 2d84241a..edbbfa40 100644 --- a/iptables/nft-ruleparse.c +++ b/iptables/nft-ruleparse.c @@ -78,8 +78,8 @@ nft_create_match(struct nft_xt_ctx *ctx, xs_init_match(match); - if (ctx->h->ops->parse_match) - ctx->h->ops->parse_match(match, cs); + if (ctx->h->ops->rule_parse->match) + ctx->h->ops->rule_parse->match(match, cs); return match->m->data; } @@ -168,7 +168,7 @@ static void nft_parse_meta_set(struct nft_xt_ctx *ctx, target->t = t; - ctx->h->ops->parse_target(target, ctx->cs); + ctx->h->ops->rule_parse->target(target, ctx->cs); } static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -488,16 +488,16 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->errmsg = "cmp sreg undef"; break; case NFT_XT_REG_META_DREG: - ctx->h->ops->parse_meta(ctx, sreg, e, ctx->cs); + ctx->h->ops->rule_parse->meta(ctx, sreg, e, ctx->cs); break; case NFT_XT_REG_PAYLOAD: switch (sreg->payload.base) { case NFT_PAYLOAD_LL_HEADER: if (ctx->h->family == NFPROTO_BRIDGE) - ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs); break; case NFT_PAYLOAD_NETWORK_HEADER: - ctx->h->ops->parse_payload(ctx, sreg, e, ctx->cs); + ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs); break; case NFT_PAYLOAD_TRANSPORT_HEADER: nft_parse_transport(ctx, e, ctx->cs); @@ -615,8 +615,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) match->m = m; - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); + if (ctx->h->ops->rule_parse->match != NULL) + ctx->h->ops->rule_parse->match(match, ctx->cs); } static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -644,7 +644,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) target->t = t; - ctx->h->ops->parse_target(target, ctx->cs); + ctx->h->ops->rule_parse->target(target, ctx->cs); } static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -678,8 +678,8 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, struct nftnl_expr *e) { - if (ctx->h->ops->parse_lookup) - ctx->h->ops->parse_lookup(ctx, e); + if (ctx->h->ops->rule_parse->lookup) + ctx->h->ops->rule_parse->lookup(ctx, e); } static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -729,7 +729,7 @@ static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) memcpy(&target->t->data, &info, sizeof(info)); - ctx->h->ops->parse_target(target, ctx->cs); + ctx->h->ops->rule_parse->target(target, ctx->cs); } static void nft_parse_udp_range(struct nft_xt_ctx *ctx, diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h index 7fac6c79..69e98817 100644 --- a/iptables/nft-ruleparse.h +++ b/iptables/nft-ruleparse.h @@ -93,6 +93,22 @@ static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, return r; } +struct nft_ruleparse_ops { + void (*meta)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs); + void (*payload)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs); + void (*lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); + void (*match)(struct xtables_match *m, + struct iptables_command_state *cs); + void (*target)(struct xtables_target *t, + struct iptables_command_state *cs); +}; + void *nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name, bool reuse); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 2edee649..a06b263d 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -46,15 +46,6 @@ struct nft_family_ops { const struct iptables_command_state *cs_b); void (*print_payload)(struct nftnl_expr *e, struct nftnl_expr_iter *iter); - void (*parse_meta)(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *sreg, - struct nftnl_expr *e, - struct iptables_command_state *cs); - void (*parse_payload)(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *sreg, - struct nftnl_expr *e, - struct iptables_command_state *cs); - void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); void (*set_goto_flag)(struct iptables_command_state *cs); void (*print_table_header)(const char *tablename); @@ -67,11 +58,8 @@ struct nft_family_ops { void (*save_rule)(const struct iptables_command_state *cs, unsigned int format); void (*save_chain)(const struct nftnl_chain *c, const char *policy); + struct nft_ruleparse_ops *rule_parse; struct xt_cmd_parse_ops cmd_parse; - void (*parse_match)(struct xtables_match *m, - struct iptables_command_state *cs); - void (*parse_target)(struct xtables_target *t, - struct iptables_command_state *cs); void (*init_cs)(struct iptables_command_state *cs); bool (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); -- cgit v1.2.3 From 4c923250269f9ef4a7b4235f4dc127b04932a8eb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Apr 2023 15:52:14 +0200 Subject: nft: ruleparse: Create family-specific source files Extract the remaining nftnl rule parsing code from nft-.c sources into dedicated ones to complete the separation. Signed-off-by: Phil Sutter --- iptables/Makefile.am | 2 + iptables/nft-arp.c | 140 ------------- iptables/nft-bridge.c | 392 ------------------------------------- iptables/nft-cache.h | 2 + iptables/nft-ipv4.c | 108 ---------- iptables/nft-ipv6.c | 85 -------- iptables/nft-ruleparse-arp.c | 168 ++++++++++++++++ iptables/nft-ruleparse-bridge.c | 422 ++++++++++++++++++++++++++++++++++++++++ iptables/nft-ruleparse-ipv4.c | 135 +++++++++++++ iptables/nft-ruleparse-ipv6.c | 112 +++++++++++ iptables/nft-ruleparse.h | 5 + 11 files changed, 846 insertions(+), 725 deletions(-) create mode 100644 iptables/nft-ruleparse-arp.c create mode 100644 iptables/nft-ruleparse-bridge.c create mode 100644 iptables/nft-ruleparse-ipv4.c create mode 100644 iptables/nft-ruleparse-ipv6.c diff --git a/iptables/Makefile.am b/iptables/Makefile.am index d5922da6..8a722702 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -47,6 +47,8 @@ xtables_nft_multi_SOURCES += nft.c nft.h \ nft-chain.c nft-chain.h \ nft-cmd.c nft-cmd.h \ nft-ruleparse.c nft-ruleparse.h \ + nft-ruleparse-arp.c nft-ruleparse-bridge.c \ + nft-ruleparse-ipv4.c nft-ruleparse-ipv6.c \ nft-shared.c nft-shared.h \ xtables-monitor.c \ xtables.c xtables-arp.c xtables-eb.c \ diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index d2756309..265de5f8 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -160,141 +160,6 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, return ret; } -static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct arpt_entry *fw = &cs->arp; - uint8_t flags = 0; - - if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, - fw->arp.outiface, fw->arp.outiface_mask, - &flags) == 0) { - fw->arp.invflags |= flags; - return; - } - - ctx->errmsg = "Unknown arp meta key"; -} - -static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) -{ - mask->s_addr = reg->bitwise.mask[0]; -} - -static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct arpt_devaddr_info *info) -{ - uint32_t hlen; - bool inv; - - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); - - if (hlen != ETH_ALEN) - return false; - - get_cmp_data(e, info->addr, ETH_ALEN, &inv); - - if (reg->bitwise.set) - memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); - else - memset(info->mask, 0xff, - min(reg->payload.len, ETH_ALEN)); - - return inv; -} - -static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct arpt_entry *fw = &cs->arp; - struct in_addr addr; - uint16_t ar_hrd, ar_pro, ar_op; - uint8_t ar_hln, ar_pln; - bool inv; - - switch (reg->payload.offset) { - case offsetof(struct arphdr, ar_hrd): - get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); - fw->arp.arhrd = ar_hrd; - fw->arp.arhrd_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPHRD; - break; - case offsetof(struct arphdr, ar_pro): - get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv); - fw->arp.arpro = ar_pro; - fw->arp.arpro_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_PROTO; - break; - case offsetof(struct arphdr, ar_op): - get_cmp_data(e, &ar_op, sizeof(ar_op), &inv); - fw->arp.arpop = ar_op; - fw->arp.arpop_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPOP; - break; - case offsetof(struct arphdr, ar_hln): - get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); - fw->arp.arhln = ar_hln; - fw->arp.arhln_mask = 0xff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPHLN; - break; - case offsetof(struct arphdr, ar_pln): - get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); - if (ar_pln != 4 || inv) - ctx->errmsg = "unexpected ARP protocol length match"; - break; - default: - if (reg->payload.offset == sizeof(struct arphdr)) { - if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) - fw->arp.invflags |= IPT_INV_SRCDEVADDR; - } else if (reg->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln) { - get_cmp_data(e, &addr, sizeof(addr), &inv); - fw->arp.src.s_addr = addr.s_addr; - if (reg->bitwise.set) - parse_mask_ipv4(reg, &fw->arp.smsk); - else - memset(&fw->arp.smsk, 0xff, - min(reg->payload.len, - sizeof(struct in_addr))); - - if (inv) - fw->arp.invflags |= IPT_INV_SRCIP; - } else if (reg->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln + - sizeof(struct in_addr)) { - if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) - fw->arp.invflags |= IPT_INV_TGTDEVADDR; - } else if (reg->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln + - sizeof(struct in_addr) + - fw->arp.arhln) { - get_cmp_data(e, &addr, sizeof(addr), &inv); - fw->arp.tgt.s_addr = addr.s_addr; - if (reg->bitwise.set) - parse_mask_ipv4(reg, &fw->arp.tmsk); - else - memset(&fw->arp.tmsk, 0xff, - min(reg->payload.len, - sizeof(struct in_addr))); - - if (inv) - fw->arp.invflags |= IPT_INV_DSTIP; - } else { - ctx->errmsg = "unknown payload offset"; - } - break; - } -} - static void nft_arp_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, @@ -781,11 +646,6 @@ nft_arp_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } -static struct nft_ruleparse_ops nft_ruleparse_ops_arp = { - .meta = nft_arp_parse_meta, - .payload = nft_arp_parse_payload, - .target = nft_ipv46_parse_target, -}; struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 0c9e1238..f3dfa488 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -231,390 +231,6 @@ static int nft_bridge_add(struct nft_handle *h, return _add_action(r, cs); } -static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - uint8_t invflags = 0; - char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - - switch (reg->meta_dreg.key) { - case NFT_META_PROTOCOL: - return; - } - - if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { - ctx->errmsg = "unknown meta key"; - return; - } - - switch (reg->meta_dreg.key) { - case NFT_META_BRI_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_ILOGICALIN; - snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname); - break; - case NFT_META_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_IIN; - snprintf(fw->in, sizeof(fw->in), "%s", iifname); - break; - case NFT_META_BRI_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_ILOGICALOUT; - snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname); - break; - case NFT_META_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_IOUT; - snprintf(fw->out, sizeof(fw->out), "%s", oifname); - break; - default: - ctx->errmsg = "unknown bridge meta key"; - break; - } -} - -static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - unsigned char addr[ETH_ALEN]; - unsigned short int ethproto; - uint8_t op; - bool inv; - int i; - - switch (reg->payload.offset) { - case offsetof(struct ethhdr, h_dest): - get_cmp_data(e, addr, sizeof(addr), &inv); - for (i = 0; i < ETH_ALEN; i++) - fw->destmac[i] = addr[i]; - if (inv) - fw->invflags |= EBT_IDEST; - - if (reg->bitwise.set) - memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); - else - memset(&fw->destmsk, 0xff, - min(reg->payload.len, ETH_ALEN)); - fw->bitmask |= EBT_IDEST; - break; - case offsetof(struct ethhdr, h_source): - get_cmp_data(e, addr, sizeof(addr), &inv); - for (i = 0; i < ETH_ALEN; i++) - fw->sourcemac[i] = addr[i]; - if (inv) - fw->invflags |= EBT_ISOURCE; - if (reg->bitwise.set) - memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); - else - memset(&fw->sourcemsk, 0xff, - min(reg->payload.len, ETH_ALEN)); - fw->bitmask |= EBT_ISOURCE; - break; - case offsetof(struct ethhdr, h_proto): - __get_cmp_data(e, ðproto, sizeof(ethproto), &op); - if (ethproto == htons(0x0600)) { - fw->bitmask |= EBT_802_3; - inv = (op == NFT_CMP_GTE); - } else { - fw->ethproto = ethproto; - inv = (op == NFT_CMP_NEQ); - } - if (inv) - fw->invflags |= EBT_IPROTO; - fw->bitmask &= ~EBT_NOPROTO; - break; - default: - DEBUGP("unknown payload offset %d\n", reg->payload.offset); - ctx->errmsg = "unknown payload offset"; - break; - } -} - -/* return 0 if saddr, 1 if daddr, -1 on error */ -static int -lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len) -{ - if (base != 0 || len != ETH_ALEN) - return -1; - - switch (offset) { - case offsetof(struct ether_header, ether_dhost): - return 1; - case offsetof(struct ether_header, ether_shost): - return 0; - default: - return -1; - } -} - -/* return 0 if saddr, 1 if daddr, -1 on error */ -static int -lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) -{ - if (base != 1 || len != 4) - return -1; - - switch (offset) { - case offsetof(struct iphdr, daddr): - return 1; - case offsetof(struct iphdr, saddr): - return 0; - default: - return -1; - } -} - -/* Make sure previous payload expression(s) is/are consistent and extract if - * matching on source or destination address and if matching on MAC and IP or - * only MAC address. */ -static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, - enum nft_registers sreg, - uint32_t key_len, - bool *dst, bool *ip) -{ - const struct nft_xt_ctx_reg *reg; - int val, val2 = -1; - - reg = nft_xt_ctx_get_sreg(ctx, sreg); - if (!reg) - return -1; - - if (reg->type != NFT_XT_REG_PAYLOAD) { - ctx->errmsg = "lookup reg is not payload type"; - return -1; - } - - switch (key_len) { - case 12: /* ether + ipv4addr */ - val = lookup_check_ether_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } - - sreg = nft_get_next_reg(sreg, ETH_ALEN); - - reg = nft_xt_ctx_get_sreg(ctx, sreg); - if (!reg) { - ctx->errmsg = "next lookup register is invalid"; - return -1; - } - - if (reg->type != NFT_XT_REG_PAYLOAD) { - ctx->errmsg = "next lookup reg is not payload type"; - return -1; - } - - val2 = lookup_check_iphdr_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val2 < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } else if (val != val2) { - DEBUGP("mismatching payload match offsets\n"); - return -1; - } - break; - case 6: /* ether */ - val = lookup_check_ether_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } - break; - default: - ctx->errmsg = "unsupported lookup key length"; - return -1; - } - - if (dst) - *dst = (val == 1); - if (ip) - *ip = (val2 != -1); - return 0; -} - -static int set_elems_to_among_pairs(struct nft_among_pair *pairs, - const struct nftnl_set *s, int cnt) -{ - struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s); - struct nftnl_set_elem *elem; - size_t tmpcnt = 0; - const void *data; - uint32_t datalen; - int ret = -1; - - if (!iter) { - fprintf(stderr, "BUG: set elems iter allocation failed\n"); - return ret; - } - - while ((elem = nftnl_set_elems_iter_next(iter))) { - data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen); - if (!data) { - fprintf(stderr, "BUG: set elem without key\n"); - goto err; - } - if (datalen > sizeof(*pairs)) { - fprintf(stderr, "BUG: overlong set elem\n"); - goto err; - } - nft_among_insert_pair(pairs, &tmpcnt, data); - } - ret = 0; -err: - nftnl_set_elems_iter_destroy(iter); - return ret; -} - -static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, - const struct nftnl_expr *e) -{ - const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET); - uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID); - struct nftnl_set_list *slist; - struct nftnl_set *set; - - slist = nft_set_list_get(ctx->h, ctx->table, set_name); - if (slist) { - set = nftnl_set_list_lookup_byname(slist, set_name); - if (set) - return set; - - set = nft_set_batch_lookup_byid(ctx->h, set_id); - if (set) - return set; - } - - return NULL; -} - -static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e) -{ - struct xtables_match *match = NULL; - struct nft_among_data *among_data; - bool is_dst, have_ip, inv; - struct ebt_match *ematch; - struct nftnl_set *s; - size_t poff, size; - uint32_t cnt; - - s = set_from_lookup_expr(ctx, e); - if (!s) - xtables_error(OTHER_PROBLEM, - "BUG: lookup expression references unknown set"); - - if (lookup_analyze_payloads(ctx, - nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), - nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), - &is_dst, &have_ip)) - return; - - cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); - - for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { - if (!ematch->ismatch || strcmp(ematch->u.match->name, "among")) - continue; - - match = ematch->u.match; - among_data = (struct nft_among_data *)match->m->data; - - size = cnt + among_data->src.cnt + among_data->dst.cnt; - size *= sizeof(struct nft_among_pair); - - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_realloc(match->m, size); - break; - } - if (!match) { - match = xtables_find_match("among", XTF_TRY_LOAD, - &ctx->cs->matches); - - size = cnt * sizeof(struct nft_among_pair); - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_calloc(1, size); - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - - if (ctx->h->ops->rule_parse->match != NULL) - ctx->h->ops->rule_parse->match(match, ctx->cs); - } - if (!match) - return; - - match->m->u.match_size = size; - - inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) & - NFT_LOOKUP_F_INV); - - among_data = (struct nft_among_data *)match->m->data; - poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip); - if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) - xtables_error(OTHER_PROBLEM, - "ebtables among pair parsing failed"); -} - -static void parse_watcher(void *object, struct ebt_match **match_list, - bool ismatch) -{ - struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match)); - - if (ismatch) - m->u.match = object; - else - m->u.watcher = object; - - m->ismatch = ismatch; - if (*match_list == NULL) - *match_list = m; - else - (*match_list)->next = m; -} - -static void nft_bridge_parse_match(struct xtables_match *m, - struct iptables_command_state *cs) -{ - parse_watcher(m, &cs->match_list, true); -} - -static void nft_bridge_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - /* harcoded names :-( */ - if (strcmp(t->name, "log") == 0 || - strcmp(t->name, "nflog") == 0) { - parse_watcher(t, &cs->match_list, false); - return; - } - - cs->target = t; - cs->jumpto = t->name; -} - static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) @@ -984,14 +600,6 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, return ret; } -static struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { - .meta = nft_bridge_parse_meta, - .payload = nft_bridge_parse_payload, - .lookup = nft_bridge_parse_lookup, - .match = nft_bridge_parse_match, - .target = nft_bridge_parse_target, -}; - struct nft_family_ops nft_family_ops_bridge = { .add = nft_bridge_add, .is_same = nft_bridge_is_same, diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h index 58a01526..29ec6b5c 100644 --- a/iptables/nft-cache.h +++ b/iptables/nft-cache.h @@ -1,6 +1,8 @@ #ifndef _NFT_CACHE_H_ #define _NFT_CACHE_H_ +#include + struct nft_handle; struct nft_chain; struct nft_cmd; diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 3f769e88..6df4e46b 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -115,108 +115,6 @@ static bool nft_ipv4_is_same(const struct iptables_command_state *a, b->fw.ip.iniface_mask, b->fw.ip.outiface_mask); } -static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e) -{ - uint8_t op; - - /* we assume correct mask and xor */ - if (!reg->bitwise.set) - return false; - - /* we assume correct data */ - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - if (op == NFT_CMP_EQ) - return true; - - return false; -} - -static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - switch (reg->meta_dreg.key) { - case NFT_META_L4PROTO: - cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - cs->fw.ip.invflags |= XT_INV_PROTO; - return; - default: - break; - } - - if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, - cs->fw.ip.outiface, cs->fw.ip.outiface_mask, - &cs->fw.ip.invflags) == 0) - return; - - ctx->errmsg = "unknown ipv4 meta key"; -} - -static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) -{ - mask->s_addr = sreg->bitwise.mask[0]; -} - -static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *sreg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct in_addr addr; - uint8_t proto; - bool inv; - - switch (sreg->payload.offset) { - case offsetof(struct iphdr, saddr): - get_cmp_data(e, &addr, sizeof(addr), &inv); - cs->fw.ip.src.s_addr = addr.s_addr; - if (sreg->bitwise.set) { - parse_mask_ipv4(sreg, &cs->fw.ip.smsk); - } else { - memset(&cs->fw.ip.smsk, 0xff, - min(sreg->payload.len, sizeof(struct in_addr))); - } - - if (inv) - cs->fw.ip.invflags |= IPT_INV_SRCIP; - break; - case offsetof(struct iphdr, daddr): - get_cmp_data(e, &addr, sizeof(addr), &inv); - cs->fw.ip.dst.s_addr = addr.s_addr; - if (sreg->bitwise.set) - parse_mask_ipv4(sreg, &cs->fw.ip.dmsk); - else - memset(&cs->fw.ip.dmsk, 0xff, - min(sreg->payload.len, sizeof(struct in_addr))); - - if (inv) - cs->fw.ip.invflags |= IPT_INV_DSTIP; - break; - case offsetof(struct iphdr, protocol): - get_cmp_data(e, &proto, sizeof(proto), &inv); - cs->fw.ip.proto = proto; - if (inv) - cs->fw.ip.invflags |= IPT_INV_PROTO; - break; - case offsetof(struct iphdr, frag_off): - cs->fw.ip.flags |= IPT_F_FRAG; - inv = get_frag(sreg, e); - if (inv) - cs->fw.ip.invflags |= IPT_INV_FRAG; - break; - case offsetof(struct iphdr, ttl): - if (nft_parse_hl(ctx, e, cs) < 0) - ctx->errmsg = "invalid ttl field match"; - break; - default: - DEBUGP("unknown payload offset %d\n", sreg->payload.offset); - ctx->errmsg = "unknown payload offset"; - break; - } -} - static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs) { cs->fw.ip.flags |= IPT_F_GOTO; @@ -440,12 +338,6 @@ nft_ipv4_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } -static struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = { - .meta = nft_ipv4_parse_meta, - .payload = nft_ipv4_parse_payload, - .target = nft_ipv46_parse_target, -}; - struct nft_family_ops nft_family_ops_ipv4 = { .add = nft_ipv4_add, .is_same = nft_ipv4_is_same, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 962aaf0d..693a1c87 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -104,85 +104,6 @@ static bool nft_ipv6_is_same(const struct iptables_command_state *a, b->fw6.ipv6.outiface_mask); } -static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - switch (reg->meta_dreg.key) { - case NFT_META_L4PROTO: - cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - cs->fw6.ipv6.invflags |= XT_INV_PROTO; - return; - default: - break; - } - - if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, - cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, - cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0) - return; - - ctx->errmsg = "unknown ipv6 meta key"; -} - -static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, - struct in6_addr *mask) -{ - memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); -} - -static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct in6_addr addr; - uint8_t proto; - bool inv; - - switch (reg->payload.offset) { - case offsetof(struct ip6_hdr, ip6_src): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); - if (reg->bitwise.set) - parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); - else - memset(&cs->fw6.ipv6.smsk, 0xff, - min(reg->payload.len, sizeof(struct in6_addr))); - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; - break; - case offsetof(struct ip6_hdr, ip6_dst): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); - if (reg->bitwise.set) - parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); - else - memset(&cs->fw6.ipv6.dmsk, 0xff, - min(reg->payload.len, sizeof(struct in6_addr))); - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; - break; - case offsetof(struct ip6_hdr, ip6_nxt): - get_cmp_data(e, &proto, sizeof(proto), &inv); - cs->fw6.ipv6.proto = proto; - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; - case offsetof(struct ip6_hdr, ip6_hlim): - if (nft_parse_hl(ctx, e, cs) < 0) - ctx->errmsg = "invalid ttl field match"; - break; - default: - DEBUGP("unknown payload offset %d\n", reg->payload.offset); - ctx->errmsg = "unknown payload offset"; - break; - } -} - static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs) { cs->fw6.ipv6.flags |= IP6T_F_GOTO; @@ -409,12 +330,6 @@ nft_ipv6_replace_entry(struct nft_handle *h, return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); } -static struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = { - .meta = nft_ipv6_parse_meta, - .payload = nft_ipv6_parse_payload, - .target = nft_ipv46_parse_target, -}; - struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, diff --git a/iptables/nft-ruleparse-arp.c b/iptables/nft-ruleparse-arp.c new file mode 100644 index 00000000..b68fb06d --- /dev/null +++ b/iptables/nft-ruleparse-arp.c @@ -0,0 +1,168 @@ +/* + * (C) 2013 by Pablo Neira Ayuso + * (C) 2013 by Giuseppe Longo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct arpt_entry *fw = &cs->arp; + uint8_t flags = 0; + + if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, + fw->arp.outiface, fw->arp.outiface_mask, + &flags) == 0) { + fw->arp.invflags |= flags; + return; + } + + ctx->errmsg = "Unknown arp meta key"; +} + +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) +{ + mask->s_addr = reg->bitwise.mask[0]; +} + +static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct arpt_devaddr_info *info) +{ + uint32_t hlen; + bool inv; + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); + + if (hlen != ETH_ALEN) + return false; + + get_cmp_data(e, info->addr, ETH_ALEN, &inv); + + if (reg->bitwise.set) + memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); + else + memset(info->mask, 0xff, + min(reg->payload.len, ETH_ALEN)); + + return inv; +} + +static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct arpt_entry *fw = &cs->arp; + struct in_addr addr; + uint16_t ar_hrd, ar_pro, ar_op; + uint8_t ar_hln, ar_pln; + bool inv; + + switch (reg->payload.offset) { + case offsetof(struct arphdr, ar_hrd): + get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); + fw->arp.arhrd = ar_hrd; + fw->arp.arhrd_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHRD; + break; + case offsetof(struct arphdr, ar_pro): + get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv); + fw->arp.arpro = ar_pro; + fw->arp.arpro_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_PROTO; + break; + case offsetof(struct arphdr, ar_op): + get_cmp_data(e, &ar_op, sizeof(ar_op), &inv); + fw->arp.arpop = ar_op; + fw->arp.arpop_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPOP; + break; + case offsetof(struct arphdr, ar_hln): + get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); + fw->arp.arhln = ar_hln; + fw->arp.arhln_mask = 0xff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHLN; + break; + case offsetof(struct arphdr, ar_pln): + get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); + if (ar_pln != 4 || inv) + ctx->errmsg = "unexpected ARP protocol length match"; + break; + default: + if (reg->payload.offset == sizeof(struct arphdr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) + fw->arp.invflags |= IPT_INV_SRCDEVADDR; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.src.s_addr = addr.s_addr; + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.smsk); + else + memset(&fw->arp.smsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_SRCIP; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) + fw->arp.invflags |= IPT_INV_TGTDEVADDR; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.tgt.s_addr = addr.s_addr; + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.tmsk); + else + memset(&fw->arp.tmsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_DSTIP; + } else { + ctx->errmsg = "unknown payload offset"; + } + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_arp = { + .meta = nft_arp_parse_meta, + .payload = nft_arp_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse-bridge.c b/iptables/nft-ruleparse-bridge.c new file mode 100644 index 00000000..50fb9283 --- /dev/null +++ b/iptables/nft-ruleparse-bridge.c @@ -0,0 +1,422 @@ +/* + * (C) 2014 by Giuseppe Longo + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +//#include +#include + +#include +#include +#include + +#include + +#include "nft.h" /* just for nft_set_batch_lookup_byid? */ +#include "nft-bridge.h" +#include "nft-cache.h" +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ebt_entry *fw = &cs->eb; + uint8_t invflags = 0; + char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; + + switch (reg->meta_dreg.key) { + case NFT_META_PROTOCOL: + return; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { + ctx->errmsg = "unknown meta key"; + return; + } + + switch (reg->meta_dreg.key) { + case NFT_META_BRI_IIFNAME: + if (invflags & IPT_INV_VIA_IN) + cs->eb.invflags |= EBT_ILOGICALIN; + snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname); + break; + case NFT_META_IIFNAME: + if (invflags & IPT_INV_VIA_IN) + cs->eb.invflags |= EBT_IIN; + snprintf(fw->in, sizeof(fw->in), "%s", iifname); + break; + case NFT_META_BRI_OIFNAME: + if (invflags & IPT_INV_VIA_OUT) + cs->eb.invflags |= EBT_ILOGICALOUT; + snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname); + break; + case NFT_META_OIFNAME: + if (invflags & IPT_INV_VIA_OUT) + cs->eb.invflags |= EBT_IOUT; + snprintf(fw->out, sizeof(fw->out), "%s", oifname); + break; + default: + ctx->errmsg = "unknown bridge meta key"; + break; + } +} + +static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ebt_entry *fw = &cs->eb; + unsigned char addr[ETH_ALEN]; + unsigned short int ethproto; + uint8_t op; + bool inv; + int i; + + switch (reg->payload.offset) { + case offsetof(struct ethhdr, h_dest): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->destmac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_IDEST; + + if (reg->bitwise.set) + memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); + else + memset(&fw->destmsk, 0xff, + min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_IDEST; + break; + case offsetof(struct ethhdr, h_source): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->sourcemac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_ISOURCE; + if (reg->bitwise.set) + memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); + else + memset(&fw->sourcemsk, 0xff, + min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_ISOURCE; + break; + case offsetof(struct ethhdr, h_proto): + __get_cmp_data(e, ðproto, sizeof(ethproto), &op); + if (ethproto == htons(0x0600)) { + fw->bitmask |= EBT_802_3; + inv = (op == NFT_CMP_GTE); + } else { + fw->ethproto = ethproto; + inv = (op == NFT_CMP_NEQ); + } + if (inv) + fw->invflags |= EBT_IPROTO; + fw->bitmask &= ~EBT_NOPROTO; + break; + default: + DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; + } +} + +/* return 0 if saddr, 1 if daddr, -1 on error */ +static int +lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len) +{ + if (base != 0 || len != ETH_ALEN) + return -1; + + switch (offset) { + case offsetof(struct ether_header, ether_dhost): + return 1; + case offsetof(struct ether_header, ether_shost): + return 0; + default: + return -1; + } +} + +/* return 0 if saddr, 1 if daddr, -1 on error */ +static int +lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) +{ + if (base != 1 || len != 4) + return -1; + + switch (offset) { + case offsetof(struct iphdr, daddr): + return 1; + case offsetof(struct iphdr, saddr): + return 0; + default: + return -1; + } +} + +/* Make sure previous payload expression(s) is/are consistent and extract if + * matching on source or destination address and if matching on MAC and IP or + * only MAC address. */ +static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, + enum nft_registers sreg, + uint32_t key_len, + bool *dst, bool *ip) +{ + const struct nft_xt_ctx_reg *reg; + int val, val2 = -1; + + reg = nft_xt_ctx_get_sreg(ctx, sreg); + if (!reg) + return -1; + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "lookup reg is not payload type"; + return -1; + } + + switch (key_len) { + case 12: /* ether + ipv4addr */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); + if (val < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } + + sreg = nft_get_next_reg(sreg, ETH_ALEN); + + reg = nft_xt_ctx_get_sreg(ctx, sreg); + if (!reg) { + ctx->errmsg = "next lookup register is invalid"; + return -1; + } + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "next lookup reg is not payload type"; + return -1; + } + + val2 = lookup_check_iphdr_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); + if (val2 < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } else if (val != val2) { + DEBUGP("mismatching payload match offsets\n"); + return -1; + } + break; + case 6: /* ether */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); + if (val < 0) { + DEBUGP("unknown payload base/offset/len %d/%d/%d\n", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } + break; + default: + ctx->errmsg = "unsupported lookup key length"; + return -1; + } + + if (dst) + *dst = (val == 1); + if (ip) + *ip = (val2 != -1); + return 0; +} + +static int set_elems_to_among_pairs(struct nft_among_pair *pairs, + const struct nftnl_set *s, int cnt) +{ + struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s); + struct nftnl_set_elem *elem; + size_t tmpcnt = 0; + const void *data; + uint32_t datalen; + int ret = -1; + + if (!iter) { + fprintf(stderr, "BUG: set elems iter allocation failed\n"); + return ret; + } + + while ((elem = nftnl_set_elems_iter_next(iter))) { + data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen); + if (!data) { + fprintf(stderr, "BUG: set elem without key\n"); + goto err; + } + if (datalen > sizeof(*pairs)) { + fprintf(stderr, "BUG: overlong set elem\n"); + goto err; + } + nft_among_insert_pair(pairs, &tmpcnt, data); + } + ret = 0; +err: + nftnl_set_elems_iter_destroy(iter); + return ret; +} + +static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, + const struct nftnl_expr *e) +{ + const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET); + uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID); + struct nftnl_set_list *slist; + struct nftnl_set *set; + + slist = nft_set_list_get(ctx->h, ctx->table, set_name); + if (slist) { + set = nftnl_set_list_lookup_byname(slist, set_name); + if (set) + return set; + + set = nft_set_batch_lookup_byid(ctx->h, set_id); + if (set) + return set; + } + + return NULL; +} + +static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) +{ + struct xtables_match *match = NULL; + struct nft_among_data *among_data; + bool is_dst, have_ip, inv; + struct ebt_match *ematch; + struct nftnl_set *s; + size_t poff, size; + uint32_t cnt; + + s = set_from_lookup_expr(ctx, e); + if (!s) + xtables_error(OTHER_PROBLEM, + "BUG: lookup expression references unknown set"); + + if (lookup_analyze_payloads(ctx, + nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), + nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), + &is_dst, &have_ip)) + return; + + cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); + + for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { + if (!ematch->ismatch || strcmp(ematch->u.match->name, "among")) + continue; + + match = ematch->u.match; + among_data = (struct nft_among_data *)match->m->data; + + size = cnt + among_data->src.cnt + among_data->dst.cnt; + size *= sizeof(struct nft_among_pair); + + size += XT_ALIGN(sizeof(struct xt_entry_match)) + + sizeof(struct nft_among_data); + + match->m = xtables_realloc(match->m, size); + break; + } + if (!match) { + match = xtables_find_match("among", XTF_TRY_LOAD, + &ctx->cs->matches); + + size = cnt * sizeof(struct nft_among_pair); + size += XT_ALIGN(sizeof(struct xt_entry_match)) + + sizeof(struct nft_among_data); + + match->m = xtables_calloc(1, size); + strcpy(match->m->u.user.name, match->name); + match->m->u.user.revision = match->revision; + xs_init_match(match); + + if (ctx->h->ops->rule_parse->match != NULL) + ctx->h->ops->rule_parse->match(match, ctx->cs); + } + if (!match) + return; + + match->m->u.match_size = size; + + inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) & + NFT_LOOKUP_F_INV); + + among_data = (struct nft_among_data *)match->m->data; + poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip); + if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) + xtables_error(OTHER_PROBLEM, + "ebtables among pair parsing failed"); +} + +static void parse_watcher(void *object, struct ebt_match **match_list, + bool ismatch) +{ + struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match)); + + if (ismatch) + m->u.match = object; + else + m->u.watcher = object; + + m->ismatch = ismatch; + if (*match_list == NULL) + *match_list = m; + else + (*match_list)->next = m; +} + +static void nft_bridge_parse_match(struct xtables_match *m, + struct iptables_command_state *cs) +{ + parse_watcher(m, &cs->match_list, true); +} + +static void nft_bridge_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) +{ + /* harcoded names :-( */ + if (strcmp(t->name, "log") == 0 || + strcmp(t->name, "nflog") == 0) { + parse_watcher(t, &cs->match_list, false); + return; + } + + cs->target = t; + cs->jumpto = t->name; +} + +struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { + .meta = nft_bridge_parse_meta, + .payload = nft_bridge_parse_payload, + .lookup = nft_bridge_parse_lookup, + .match = nft_bridge_parse_match, + .target = nft_bridge_parse_target, +}; diff --git a/iptables/nft-ruleparse-ipv4.c b/iptables/nft-ruleparse-ipv4.c new file mode 100644 index 00000000..c87e159c --- /dev/null +++ b/iptables/nft-ruleparse-ipv4.c @@ -0,0 +1,135 @@ +/* + * (C) 2012-2014 by Pablo Neira Ayuso + * (C) 2013 by Tomasz Bursztyka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + cs->fw.ip.invflags |= XT_INV_PROTO; + return; + default: + break; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + cs->fw.ip.outiface, cs->fw.ip.outiface_mask, + &cs->fw.ip.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv4 meta key"; +} + +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) +{ + mask->s_addr = sreg->bitwise.mask[0]; +} + +static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e) +{ + uint8_t op; + + /* we assume correct mask and xor */ + if (!reg->bitwise.set) + return false; + + /* we assume correct data */ + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + if (op == NFT_CMP_EQ) + return true; + + return false; +} + +static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct in_addr addr; + uint8_t proto; + bool inv; + + switch (sreg->payload.offset) { + case offsetof(struct iphdr, saddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.src.s_addr = addr.s_addr; + if (sreg->bitwise.set) { + parse_mask_ipv4(sreg, &cs->fw.ip.smsk); + } else { + memset(&cs->fw.ip.smsk, 0xff, + min(sreg->payload.len, sizeof(struct in_addr))); + } + + if (inv) + cs->fw.ip.invflags |= IPT_INV_SRCIP; + break; + case offsetof(struct iphdr, daddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.dst.s_addr = addr.s_addr; + if (sreg->bitwise.set) + parse_mask_ipv4(sreg, &cs->fw.ip.dmsk); + else + memset(&cs->fw.ip.dmsk, 0xff, + min(sreg->payload.len, sizeof(struct in_addr))); + + if (inv) + cs->fw.ip.invflags |= IPT_INV_DSTIP; + break; + case offsetof(struct iphdr, protocol): + get_cmp_data(e, &proto, sizeof(proto), &inv); + cs->fw.ip.proto = proto; + if (inv) + cs->fw.ip.invflags |= IPT_INV_PROTO; + break; + case offsetof(struct iphdr, frag_off): + cs->fw.ip.flags |= IPT_F_FRAG; + inv = get_frag(sreg, e); + if (inv) + cs->fw.ip.invflags |= IPT_INV_FRAG; + break; + case offsetof(struct iphdr, ttl): + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; + break; + default: + DEBUGP("unknown payload offset %d\n", sreg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = { + .meta = nft_ipv4_parse_meta, + .payload = nft_ipv4_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse-ipv6.c b/iptables/nft-ruleparse-ipv6.c new file mode 100644 index 00000000..af55420b --- /dev/null +++ b/iptables/nft-ruleparse-ipv6.c @@ -0,0 +1,112 @@ +/* + * (C) 2012-2014 by Pablo Neira Ayuso + * (C) 2013 by Tomasz Bursztyka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + cs->fw6.ipv6.invflags |= XT_INV_PROTO; + return; + default: + break; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, + cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, + cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv6 meta key"; +} + +static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, + struct in6_addr *mask) +{ + memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); +} + +static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct in6_addr addr; + uint8_t proto; + bool inv; + + switch (reg->payload.offset) { + case offsetof(struct ip6_hdr, ip6_src): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); + else + memset(&cs->fw6.ipv6.smsk, 0xff, + min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; + break; + case offsetof(struct ip6_hdr, ip6_dst): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); + else + memset(&cs->fw6.ipv6.dmsk, 0xff, + min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; + break; + case offsetof(struct ip6_hdr, ip6_nxt): + get_cmp_data(e, &proto, sizeof(proto), &inv); + cs->fw6.ipv6.proto = proto; + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; + case offsetof(struct ip6_hdr, ip6_hlim): + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; + break; + default: + DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = { + .meta = nft_ipv6_parse_meta, + .payload = nft_ipv6_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h index 69e98817..fd083c08 100644 --- a/iptables/nft-ruleparse.h +++ b/iptables/nft-ruleparse.h @@ -109,6 +109,11 @@ struct nft_ruleparse_ops { struct iptables_command_state *cs); }; +extern struct nft_ruleparse_ops nft_ruleparse_ops_arp; +extern struct nft_ruleparse_ops nft_ruleparse_ops_bridge; +extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv4; +extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv6; + void *nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name, bool reuse); -- cgit v1.2.3 From f6d6ad24354ecd2997a48ba51b12e7dc34addd15 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jun 2023 21:28:28 +0200 Subject: nft: check for source and destination address in first place When generating bytecode, check for source and destination address in first place, then, check for the input and output device. In general, the first expression in the rule is the most evaluated during the evaluation process. These selectors are likely to show more variability in rulesets. # iptables-nft -vv -I INPUT -s 1.2.3.4 -p tcp tcp opt -- in * out * 1.2.3.4 -> 0.0.0.0/0 table filter ip flags 0 use 0 handle 0 ip filter INPUT use 0 type filter hook input prio 0 policy accept packets 0 bytes 0 ip filter INPUT [ payload load 4b @ network header + 12 => reg 1 ] [ cmp eq reg 1 0x04030201 ] [ meta load l4proto => reg 1 ] [ cmp eq reg 1 0x00000006 ] [ counter pkts 0 bytes 0 ] Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- iptables/nft-bridge.c | 28 ++++++++++++++-------------- iptables/nft-ipv4.c | 30 ++++++++++++++++-------------- iptables/nft-ipv6.c | 32 +++++++++++++++++--------------- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index f3dfa488..6e509507 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -163,6 +163,20 @@ static int nft_bridge_add(struct nft_handle *h, struct ebt_entry *fw = &cs->eb; uint32_t op; + if (fw->bitmask & EBT_ISOURCE) { + op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, + offsetof(struct ethhdr, h_source), + fw->sourcemac, fw->sourcemsk, ETH_ALEN, op); + } + + if (fw->bitmask & EBT_IDEST) { + op = nft_invflags2cmp(fw->invflags, EBT_IDEST); + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, + offsetof(struct ethhdr, h_dest), + fw->destmac, fw->destmsk, ETH_ALEN, op); + } + if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); add_iniface(h, r, fw->in, op); @@ -183,20 +197,6 @@ static int nft_bridge_add(struct nft_handle *h, add_logical_outiface(h, r, fw->logical_out, op); } - if (fw->bitmask & EBT_ISOURCE) { - op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_addr(h, r, NFT_PAYLOAD_LL_HEADER, - offsetof(struct ethhdr, h_source), - fw->sourcemac, fw->sourcemsk, ETH_ALEN, op); - } - - if (fw->bitmask & EBT_IDEST) { - op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_addr(h, r, NFT_PAYLOAD_LL_HEADER, - offsetof(struct ethhdr, h_dest), - fw->destmac, fw->destmsk, ETH_ALEN, op); - } - if ((fw->bitmask & EBT_NOPROTO) == 0) { uint16_t ethproto = fw->ethproto; uint8_t reg; diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 6df4e46b..d67d8198 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -33,6 +33,22 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, uint32_t op; int ret; + if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { + op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, + offsetof(struct iphdr, saddr), + &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, + sizeof(struct in_addr), op); + } + + if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { + op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, + offsetof(struct iphdr, daddr), + &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, + sizeof(struct in_addr), op); + } + if (cs->fw.ip.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN); add_iniface(h, r, cs->fw.ip.iniface, op); @@ -48,20 +64,6 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, add_l4proto(h, r, cs->fw.ip.proto, op); } - if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { - op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); - add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, - offsetof(struct iphdr, saddr), - &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, - sizeof(struct in_addr), op); - } - if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { - op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); - add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, - offsetof(struct iphdr, daddr), - &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, - sizeof(struct in_addr), op); - } if (cs->fw.ip.flags & IPT_F_FRAG) { uint8_t reg; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 693a1c87..658a4f20 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -32,21 +32,6 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, uint32_t op; int ret; - if (cs->fw6.ipv6.iniface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, cs->fw6.ipv6.iniface, op); - } - - if (cs->fw6.ipv6.outiface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, cs->fw6.ipv6.outiface, op); - } - - if (cs->fw6.ipv6.proto != 0) { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); - add_l4proto(h, r, cs->fw6.ipv6.proto, op); - } - if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) || (cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) { @@ -56,6 +41,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, sizeof(struct in6_addr), op); } + if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) || (cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) { @@ -65,6 +51,22 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, sizeof(struct in6_addr), op); } + + if (cs->fw6.ipv6.iniface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); + add_iniface(h, r, cs->fw6.ipv6.iniface, op); + } + + if (cs->fw6.ipv6.outiface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); + add_outiface(h, r, cs->fw6.ipv6.outiface, op); + } + + if (cs->fw6.ipv6.proto != 0) { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); + add_l4proto(h, r, cs->fw6.ipv6.proto, op); + } + add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { -- cgit v1.2.3 From 3513f2dd8b9c101dcecee6145a7eac62297ca1c8 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Sun, 11 Jun 2023 12:34:29 +0100 Subject: man: string: document BM false negatives For non-linear skb's there's a possibility that the kernel's Boyer-Moore text-search implementation may miss matches. There's a warning about this in the kernel source. Include that warning in the man-page. Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1390 Signed-off-by: Jeremy Sowden Signed-off-by: Phil Sutter --- extensions/libxt_string.man | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man index 5f1a993c..2a470ece 100644 --- a/extensions/libxt_string.man +++ b/extensions/libxt_string.man @@ -29,3 +29,18 @@ iptables \-A INPUT \-p tcp \-\-dport 80 \-m string \-\-algo bm \-\-string 'GET / # The hex string pattern can be used for non-printable characters, like |0D 0A| or |0D0A|. .br iptables \-p udp \-\-dport 53 \-m string \-\-algo bm \-\-from 40 \-\-to 57 \-\-hex\-string '|03|www|09|netfilter|03|org|00|' +.P +Note: Since Boyer-Moore (BM) performs searches for matches from right to left and +the kernel may store a packet in multiple discontiguous blocks, it's possible +that a match could be spread over multiple blocks, in which case this algorithm +won't find it. +.P +If you wish to ensure that such thing won't ever happen, use the +Knuth-Pratt-Morris (KMP) algorithm instead. In conclusion, choose the proper +string search algorithm depending on your use-case. +.P +For example, if you're using the module for filtering, NIDS or any similar +security-focused purpose, then choose KMP. On the other hand, if you really care +about performance \(em for example, you're classifying packets to apply Quality +of Service (QoS) policies \(em and you don't mind about missing possible matches +spread over multiple fragments, then choose BM. -- cgit v1.2.3 From 69278f9602b43df80821c55c21c0666f5c6f7e2f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 9 Jun 2023 12:30:30 +0200 Subject: nft: use payload matching for layer 4 protocol This is an IPv4 header, which does not require the special handling as in IPv6, use the payload matching instead of meta l4proto which is slightly faster in this case. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- iptables/nft-ipv4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index d67d8198..2a5d25d8 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -61,7 +61,8 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, if (cs->fw.ip.proto != 0) { op = nft_invflags2cmp(cs->fw.ip.invflags, XT_INV_PROTO); - add_l4proto(h, r, cs->fw.ip.proto, op); + add_proto(h, r, offsetof(struct iphdr, protocol), + sizeof(uint8_t), cs->fw.ip.proto, op); } if (cs->fw.ip.flags & IPT_F_FRAG) { -- cgit v1.2.3 From 15919abe32092561c6318ebe2b0a9aa51e746bde Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 30 May 2023 18:11:09 +0200 Subject: xshared: dissolve should_load_proto cs->proto_used already tells whether -p foo was turned into an implicit -m foo once, so I do not think should_load_proto() has a reason to exist. Signed-off-by: Jan Engelhardt Signed-off-by: Phil Sutter --- iptables/xshared.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 17aed04e..a2350103 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -111,20 +111,13 @@ find_proto(const char *pname, enum xtables_tryload tryload, * [think of ip6tables-restore!] * - the protocol extension can be successively loaded */ -static bool should_load_proto(struct iptables_command_state *cs) -{ - if (cs->protocol == NULL) - return false; - if (find_proto(cs->protocol, XTF_DONT_LOAD, - cs->options & OPT_NUMERIC, NULL) == NULL) - return true; - return !cs->proto_used; -} - static struct xtables_match *load_proto(struct iptables_command_state *cs) { - if (!should_load_proto(cs)) + if (cs->protocol == NULL) return NULL; + if (cs->proto_used) + return NULL; + cs->proto_used = true; return find_proto(cs->protocol, XTF_TRY_LOAD, cs->options & OPT_NUMERIC, &cs->matches); } @@ -157,13 +150,10 @@ static int command_default(struct iptables_command_state *cs, return 0; } - /* Try loading protocol */ m = load_proto(cs); if (m != NULL) { size_t size; - cs->proto_used = 1; - size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; m->m = xtables_calloc(1, size); -- cgit v1.2.3 From ed839159edf8bda8e9196f1056c4038c22d78bfd Mon Sep 17 00:00:00 2001 From: Jacek Tomasiak Date: Mon, 19 Jun 2023 12:44:54 +0200 Subject: iptables: Fix setting of ipv6 counters When setting counters using ip6tables-nft -c X Y the X and Y values were not stored. This is a fix based on 9baf3bf0e77dab6ca4b167554ec0e57b65d0af01 but applied to the nft variant of ipv6 not the legacy. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1647 Fixes: 0391677c1a0b2 ("xtables: add IPv6 support") Signed-off-by: Jacek Tomasiak Signed-off-by: Jacek Tomasiak Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 | 6 +++--- iptables/tests/shell/testcases/iptables/0003-list-rules_0 | 6 +++--- iptables/xshared.c | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 b/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 index c98bdd6e..09e39927 100755 --- a/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 +++ b/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 @@ -3,7 +3,7 @@ set -e $XT_MULTI ip6tables -N foo -$XT_MULTI ip6tables -A FORWARD -i eth23 -o eth42 -j ACCEPT +$XT_MULTI ip6tables -A FORWARD -i eth23 -o eth42 -j ACCEPT -c 23 42 $XT_MULTI ip6tables -A FORWARD -i eth42 -o eth23 -g foo $XT_MULTI ip6tables -t nat -A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT @@ -20,7 +20,7 @@ EXPECT='-P INPUT ACCEPT -c 0 0 -P FORWARD ACCEPT -c 0 0 -P OUTPUT ACCEPT -c 0 0 -N foo --A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT +-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT -A FORWARD -i eth42 -o eth23 -c 0 0 -g foo' diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -v -S) @@ -32,7 +32,7 @@ EXPECT='-P FORWARD ACCEPT diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -S FORWARD) EXPECT='-P FORWARD ACCEPT -c 0 0 --A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT +-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT -A FORWARD -i eth42 -o eth23 -c 0 0 -g foo' diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -v -S FORWARD) diff --git a/iptables/tests/shell/testcases/iptables/0003-list-rules_0 b/iptables/tests/shell/testcases/iptables/0003-list-rules_0 index d335d442..d07bd151 100755 --- a/iptables/tests/shell/testcases/iptables/0003-list-rules_0 +++ b/iptables/tests/shell/testcases/iptables/0003-list-rules_0 @@ -3,7 +3,7 @@ set -e $XT_MULTI iptables -N foo -$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j ACCEPT +$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j ACCEPT -c 23 42 $XT_MULTI iptables -A FORWARD -i eth42 -o eth23 -g foo $XT_MULTI iptables -t nat -A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT @@ -20,7 +20,7 @@ EXPECT='-P INPUT ACCEPT -c 0 0 -P FORWARD ACCEPT -c 0 0 -P OUTPUT ACCEPT -c 0 0 -N foo --A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT +-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT -A FORWARD -i eth42 -o eth23 -c 0 0 -g foo' diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S) @@ -32,7 +32,7 @@ EXPECT='-P FORWARD ACCEPT diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S FORWARD) EXPECT='-P FORWARD ACCEPT -c 0 0 --A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT +-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT -A FORWARD -i eth42 -o eth23 -c 0 0 -g foo' diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S FORWARD) diff --git a/iptables/xshared.c b/iptables/xshared.c index a2350103..28c65fae 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1982,6 +1982,9 @@ void ipv6_post_parse(int command, struct iptables_command_state *cs, if (args->goto_set) cs->fw6.ipv6.flags |= IP6T_F_GOTO; + /* nft-variants use cs->counters, legacy uses cs->fw6.counters */ + cs->counters.pcnt = args->pcnt_cnt; + cs->counters.bcnt = args->bcnt_cnt; cs->fw6.counters.pcnt = args->pcnt_cnt; cs->fw6.counters.bcnt = args->bcnt_cnt; -- cgit v1.2.3 From 82ccfb488eeac5507471099b9b4e6d136cc06e3b Mon Sep 17 00:00:00 2001 From: Jacek Tomasiak Date: Mon, 19 Jun 2023 13:46:36 +0200 Subject: iptables: Fix handling of non-existent chains Since 694612adf87 the "compatibility" check considers non-existent chains as "incompatible". This broke some scripts which used calls like `iptables -L CHAIN404` to test for chain existence and expect "No chain/target/match by that name." in the output. This patch changes the logic of `nft_is_table_compatible()` to report non-existent chains as "compatible" which restores the old behavior. Fixes: 694612adf87 ("nft: Fix selective chain compatibility checks") Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1648 Signed-off-by: Jacek Tomasiak Signed-off-by: Jacek Tomasiak Signed-off-by: Phil Sutter --- iptables/nft.c | 2 +- iptables/tests/shell/testcases/iptables/0004-return-codes_0 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iptables/nft.c b/iptables/nft.c index 1cb104e7..020553a4 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3860,7 +3860,7 @@ bool nft_is_table_compatible(struct nft_handle *h, if (chain) { struct nft_chain *c = nft_chain_find(h, table, chain); - return c && !nft_is_chain_compatible(c, h); + return !c || !nft_is_chain_compatible(c, h); } return !nft_chain_foreach(h, table, nft_is_chain_compatible, h); diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 index 33c5f1f3..234f3040 100755 --- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 @@ -58,6 +58,7 @@ cmd 1 "$ENOENT" -Z bar cmd 0 -E foo bar cmd 1 "$EEXIST_F" -E foo bar cmd 1 "$ENOENT" -E foo bar2 +cmd 1 "$ENOENT" -L foo cmd 0 -N foo2 cmd 1 "$EEXIST_F" -E foo2 bar -- cgit v1.2.3 From 4e95200ded923f0eb5579c33b91176193c59dbe0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 11 Jul 2023 22:06:44 +0200 Subject: nft-bridge: pass context structure to ops->add() to improve anonymous set support Add context structure to improve bridge among support which creates an anonymous set. This context structure specifies the command and it allows to optionally store a anonymous set. Use this context to generate native bytecode only if this is an add/insert/replace command. This fixes a dangling anonymous set that is created on rule removal. Fixes: 26753888720d ("nft: bridge: Rudimental among extension support") Reported-and-tested-by: Igor Raits Signed-off-by: Pablo Neira Ayuso --- iptables/nft-arp.c | 4 ++-- iptables/nft-bridge.c | 9 +++++---- iptables/nft-cmd.c | 6 +++++- iptables/nft-ipv4.c | 6 +++--- iptables/nft-ipv6.c | 6 +++--- iptables/nft-shared.h | 5 +++-- iptables/nft.c | 54 +++++++++++++++++++++++++++++++++------------------ iptables/nft.h | 9 ++++++--- 8 files changed, 62 insertions(+), 37 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 265de5f8..9868966a 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -40,8 +40,8 @@ static bool need_devaddr(struct arpt_devaddr_info *info) return false; } -static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs) +static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs) { struct arpt_entry *fw = &cs->arp; uint32_t op; diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 6e509507..391a8ab7 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -138,7 +138,8 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) static int nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, - struct nftnl_rule *r, struct xt_entry_match *m) + struct nft_rule_ctx *ctx, struct nftnl_rule *r, + struct xt_entry_match *m) { if (!strcmp(m->u.user.name, "802_3") && !(fw->bitmask & EBT_802_3)) xtables_error(PARAMETER_PROBLEM, @@ -152,10 +153,10 @@ nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, xtables_error(PARAMETER_PROBLEM, "For IPv6 filtering the protocol must be specified as IPv6."); - return add_match(h, r, m); + return add_match(h, ctx, r, m); } -static int nft_bridge_add(struct nft_handle *h, +static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct iptables_command_state *cs) { @@ -217,7 +218,7 @@ static int nft_bridge_add(struct nft_handle *h, for (iter = cs->match_list; iter; iter = iter->next) { if (iter->ismatch) { - if (nft_bridge_add_match(h, fw, r, iter->u.match->m)) + if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m)) break; } else { if (add_target(r, iter->u.watcher->t)) diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 7b2fc3a5..8a824586 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -14,12 +14,16 @@ #include #include "nft.h" #include "nft-cmd.h" +#include struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, const char *table, const char *chain, struct iptables_command_state *state, int rulenum, bool verbose) { + struct nft_rule_ctx ctx = { + .command = command, + }; struct nftnl_rule *rule; struct nft_cmd *cmd; @@ -33,7 +37,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, cmd->verbose = verbose; if (state) { - rule = nft_rule_new(h, chain, table, state); + rule = nft_rule_new(h, &ctx, chain, table, state); if (!rule) { nft_cmd_free(cmd); return NULL; diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 2a5d25d8..2f10220e 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -26,8 +26,8 @@ #include "nft.h" #include "nft-shared.h" -static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs) +static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs) { struct xtables_rule_match *matchp; uint32_t op; @@ -84,7 +84,7 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { - ret = add_match(h, r, matchp->match->m); + ret = add_match(h, ctx, r, matchp->match->m); if (ret < 0) return ret; } diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 658a4f20..d53f87c1 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -25,8 +25,8 @@ #include "nft.h" #include "nft-shared.h" -static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs) +static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs) { struct xtables_rule_match *matchp; uint32_t op; @@ -70,7 +70,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { - ret = add_match(h, r, matchp->match->m); + ret = add_match(h, ctx, r, matchp->match->m); if (ret < 0) return ret; } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index a06b263d..4f47058d 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -35,13 +35,14 @@ | FMT_NUMERIC | FMT_NOTABLE) #define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) +struct nft_rule_ctx; struct xtables_args; struct nft_handle; struct xt_xlate; struct nft_family_ops { - int (*add)(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs); + int (*add)(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs); bool (*is_same)(const struct iptables_command_state *cs_a, const struct iptables_command_state *cs_b); void (*print_payload)(struct nftnl_expr *e, diff --git a/iptables/nft.c b/iptables/nft.c index 020553a4..230946d3 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1154,7 +1154,8 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags) #define NFT_DATATYPE_ETHERADDR 9 static int __add_nft_among(struct nft_handle *h, const char *table, - struct nftnl_rule *r, struct nft_among_pair *pairs, + struct nft_rule_ctx *ctx, struct nftnl_rule *r, + struct nft_among_pair *pairs, int cnt, bool dst, bool inv, bool ip) { uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN; @@ -1235,7 +1236,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table, return 0; } -static int add_nft_among(struct nft_handle *h, +static int add_nft_among(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct xt_entry_match *m) { struct nft_among_data *data = (struct nft_among_data *)m->data; @@ -1251,10 +1252,10 @@ static int add_nft_among(struct nft_handle *h, } if (data->src.cnt) - __add_nft_among(h, table, r, data->pairs, data->src.cnt, + __add_nft_among(h, table, ctx, r, data->pairs, data->src.cnt, false, data->src.inv, data->src.ip); if (data->dst.cnt) - __add_nft_among(h, table, r, data->pairs + data->src.cnt, + __add_nft_among(h, table, ctx, r, data->pairs + data->src.cnt, data->dst.cnt, true, data->dst.inv, data->dst.ip); return 0; @@ -1462,22 +1463,30 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r, return 0; } -int add_match(struct nft_handle *h, +int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct xt_entry_match *m) { struct nftnl_expr *expr; int ret; - if (!strcmp(m->u.user.name, "limit")) - return add_nft_limit(r, m); - else if (!strcmp(m->u.user.name, "among")) - return add_nft_among(h, r, m); - else if (!strcmp(m->u.user.name, "udp")) - return add_nft_udp(h, r, m); - else if (!strcmp(m->u.user.name, "tcp")) - return add_nft_tcp(h, r, m); - else if (!strcmp(m->u.user.name, "mark")) - return add_nft_mark(h, r, m); + switch (ctx->command) { + case NFT_COMPAT_RULE_APPEND: + case NFT_COMPAT_RULE_INSERT: + case NFT_COMPAT_RULE_REPLACE: + if (!strcmp(m->u.user.name, "limit")) + return add_nft_limit(r, m); + else if (!strcmp(m->u.user.name, "among")) + return add_nft_among(h, ctx, r, m); + else if (!strcmp(m->u.user.name, "udp")) + return add_nft_udp(h, r, m); + else if (!strcmp(m->u.user.name, "tcp")) + return add_nft_tcp(h, r, m); + else if (!strcmp(m->u.user.name, "mark")) + return add_nft_mark(h, r, m); + break; + default: + break; + } expr = nftnl_expr_alloc("match"); if (expr == NULL) @@ -1705,7 +1714,8 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv) } struct nftnl_rule * -nft_rule_new(struct nft_handle *h, const char *chain, const char *table, +nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *ctx, + const char *chain, const char *table, struct iptables_command_state *cs) { struct nftnl_rule *r; @@ -1718,7 +1728,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table, nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table); nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain); - if (h->ops->add(h, r, cs) < 0) + if (h->ops->add(h, ctx, r, cs) < 0) goto err; return r; @@ -2878,6 +2888,9 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, { struct iptables_command_state cs = {}; struct nftnl_rule *r, *new_rule; + struct nft_rule_ctx ctx = { + .command = NFT_COMPAT_RULE_APPEND, + }; struct nft_chain *c; int ret = 0; @@ -2896,7 +2909,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, h->ops->rule_to_cs(h, r, &cs); cs.counters.pcnt = cs.counters.bcnt = 0; - new_rule = nft_rule_new(h, chain, table, &cs); + new_rule = nft_rule_new(h, &ctx, chain, table, &cs); h->ops->clear_cs(&cs); if (!new_rule) @@ -3274,6 +3287,9 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) .eb.bitmask = EBT_NOPROTO, }; struct nftnl_udata_buf *udata; + struct nft_rule_ctx ctx = { + .command = NFT_COMPAT_RULE_APPEND, + }; struct nft_handle *h = data; struct nftnl_rule *r; const char *pname; @@ -3301,7 +3317,7 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) command_jump(&cs, pname); - r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME), + r = nft_rule_new(h, &ctx, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME), nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs); ebt_cs_clean(&cs); diff --git a/iptables/nft.h b/iptables/nft.h index 1d18982d..5acbbf82 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -168,9 +168,11 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h, /* * Operations with rule-set. */ -struct nftnl_rule; +struct nft_rule_ctx { + int command; +}; -struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cs); +struct nftnl_rule *nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *rule, const char *chain, const char *table, struct iptables_command_state *cs); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose); int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose); int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose); @@ -188,7 +190,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char * */ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes); int add_verdict(struct nftnl_rule *r, int verdict); -int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m); +int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, + 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); -- cgit v1.2.3 From 2746726e03d9017d4c940a247590f8d5c5d5a73e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 19 Jul 2023 14:58:11 +0200 Subject: tests: shell: Sanitize nft-only/0009-needless-bitwise_0 Some versions of awk (gawk-4.2.1-4.el8 in particular) also print the non-debug ruleset listing's empty lines, causing the diff to fail. Catch this by exiting upon seeing the first table heading. For the sake of comparing bytecode, the actual ruleset listing is not interesting, anyway. Fixes: 0f7ea0390b336 ("tests/shell: Fix nft-only/0009-needless-bitwise_0") Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 index 41588a10..34802cc2 100755 --- a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 +++ b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 @@ -340,7 +340,7 @@ bridge filter OUTPUT 10 9 # - lines with bytecode (starting with ' [') # - empty lines (so printed diff is not a complete mess) filter() { - awk '/^( \[|$)/{print}' + awk '/^table /{exit} /^( \[|$)/{print}' } diff -u -Z <(filter <<< "$EXPECT") <(nft --debug=netlink list ruleset | filter) -- cgit v1.2.3 From 10583537004f7ecd4aa11f6c12b7ba73fb77fc11 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Jul 2023 13:14:36 +0200 Subject: nft: Special casing for among match in compare_matches() When other extensions may have "garbage" appended to their data which should not be considered for match comparison, among match is the opposite in that it extends its data beyond the value in 'size' field. Add special casing to cover for this, avoiding false-positive rule comparison. Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support") Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 12860fbf..0cd082b5 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -381,6 +381,7 @@ bool compare_matches(struct xtables_rule_match *mt1, for (mp1 = mt1, mp2 = mt2; mp1 && mp2; mp1 = mp1->next, mp2 = mp2->next) { struct xt_entry_match *m1 = mp1->match->m; struct xt_entry_match *m2 = mp2->match->m; + size_t cmplen = mp1->match->userspacesize; if (strcmp(m1->u.user.name, m2->u.user.name) != 0) { DEBUGP("mismatching match name\n"); @@ -392,8 +393,10 @@ bool compare_matches(struct xtables_rule_match *mt1, return false; } - if (memcmp(m1->data, m2->data, - mp1->match->userspacesize) != 0) { + if (!strcmp(m1->u.user.name, "among")) + cmplen = m1->u.match_size - sizeof(*m1); + + if (memcmp(m1->data, m2->data, cmplen) != 0) { DEBUGP("mismatch match data\n"); return false; } -- cgit v1.2.3 From 405ee2c3fea3ebdb8ac2af183db903c81e78f528 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Jul 2023 11:15:15 +0200 Subject: nft: More verbose extension comparison debugging Dump extension data if it differs. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 2 ++ iptables/xshared.h | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 0cd082b5..34ca9d16 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -398,6 +398,8 @@ bool compare_matches(struct xtables_rule_match *mt1, if (memcmp(m1->data, m2->data, cmplen) != 0) { DEBUGP("mismatch match data\n"); + DEBUG_HEXDUMP("m1->data", m1->data, cmplen); + DEBUG_HEXDUMP("m2->data", m2->data, cmplen); return false; } } diff --git a/iptables/xshared.h b/iptables/xshared.h index 0ed9f3c2..a200e0d6 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -12,8 +12,15 @@ #ifdef DEBUG #define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#define DEBUG_HEXDUMP(pfx, data, len) \ + for (int __i = 0; __i < (len); __i++) { \ + if (__i % 16 == 0) \ + printf("%s%s: ", __i ? "\n" : "", (pfx)); \ + printf("%02x ", ((const unsigned char *)data)[__i]); \ + } printf("\n") #else #define DEBUGP(x, args...) +#define DEBUG_HEXDUMP(pfx, data, len) #endif enum { -- cgit v1.2.3 From bd71c11a95ab2b44794843fd8a3698039a7db211 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 15 Jul 2023 01:35:39 +0200 Subject: nft: Do not pass nft_rule_ctx to add_nft_among() It is not used, must be a left-over from an earlier version of the fixed commit. Fixes: 4e95200ded923 ("nft-bridge: pass context structure to ops->add() to improve anonymous set support") Signed-off-by: Phil Sutter --- iptables/nft.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 230946d3..f453f07a 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1154,8 +1154,7 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags) #define NFT_DATATYPE_ETHERADDR 9 static int __add_nft_among(struct nft_handle *h, const char *table, - struct nft_rule_ctx *ctx, struct nftnl_rule *r, - struct nft_among_pair *pairs, + struct nftnl_rule *r, struct nft_among_pair *pairs, int cnt, bool dst, bool inv, bool ip) { uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN; @@ -1236,7 +1235,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table, return 0; } -static int add_nft_among(struct nft_handle *h, struct nft_rule_ctx *ctx, +static int add_nft_among(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m) { struct nft_among_data *data = (struct nft_among_data *)m->data; @@ -1252,10 +1251,10 @@ static int add_nft_among(struct nft_handle *h, struct nft_rule_ctx *ctx, } if (data->src.cnt) - __add_nft_among(h, table, ctx, r, data->pairs, data->src.cnt, + __add_nft_among(h, table, r, data->pairs, data->src.cnt, false, data->src.inv, data->src.ip); if (data->dst.cnt) - __add_nft_among(h, table, ctx, r, data->pairs + data->src.cnt, + __add_nft_among(h, table, r, data->pairs + data->src.cnt, data->dst.cnt, true, data->dst.inv, data->dst.ip); return 0; @@ -1476,7 +1475,7 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, if (!strcmp(m->u.user.name, "limit")) return add_nft_limit(r, m); else if (!strcmp(m->u.user.name, "among")) - return add_nft_among(h, ctx, r, m); + return add_nft_among(h, r, m); else if (!strcmp(m->u.user.name, "udp")) return add_nft_udp(h, r, m); else if (!strcmp(m->u.user.name, "tcp")) -- cgit v1.2.3 From a2532c966659f386781a5757e0a1f42cb1d81573 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 15 Jul 2023 14:13:28 +0200 Subject: nft: Include sets in debug output Rules referencing them are incomplete without, so add debug output on the same level as for rules. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 10 +++++++++- iptables/nft.c | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 76e99adc..fabb5779 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -417,6 +417,7 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data) char buf[MNL_SOCKET_BUFFER_SIZE]; struct nft_handle *h = data; struct nlmsghdr *nlh; + int ret; if (set_has_elements(s)) return 0; @@ -425,7 +426,14 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data) NLM_F_DUMP, h->seq); nftnl_set_elems_nlmsg_build_payload(nlh, s); - return mnl_talk(h, nlh, set_elem_cb, s); + ret = mnl_talk(h, nlh, set_elem_cb, s); + + if (!ret && h->verbose > 1) { + fprintf(stdout, "set "); + nftnl_set_fprintf(stdout, s, 0, 0); + fprintf(stdout, "\n"); + } + return ret; } static int fetch_set_cache(struct nft_handle *h, diff --git a/iptables/nft.c b/iptables/nft.c index f453f07a..b702c65a 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2975,6 +2975,12 @@ static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type, break; } nftnl_set_elems_iter_destroy(iter); + + if (h->verbose > 1) { + fprintf(stdout, "set "); + nftnl_set_fprintf(stdout, set, 0, 0); + fprintf(stdout, "\n"); + } } static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, -- cgit v1.2.3 From 4a2b2008fdf4df980433f99a6d8f2003f2005296 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Jul 2023 19:40:30 +0200 Subject: *tables-restore: Enforce correct counters syntax if present If '--counters' option was not given, restore parsers would ignore anything following the policy word. Make them more strict, rejecting anything in that spot which does not look like counter values even if not restoring counters. Signed-off-by: Phil Sutter --- iptables/iptables-restore.c | 20 +++++++++----------- .../testcases/ipt-restore/0008-restore-counters_0 | 7 +++++++ iptables/xtables-restore.c | 18 ++++++++---------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 6f7ddf93..f11b2dc2 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -283,23 +283,21 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, xt_params->program_name, line); if (strcmp(policy, "-") != 0) { + char *ctrs = strtok(NULL, " \t\n"); 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'", - chain); - } + if ((!ctrs && counters) || + (ctrs && !parse_counters(ctrs, &count))) + xtables_error(PARAMETER_PROBLEM, + "invalid policy counters for chain '%s'", + chain); DEBUGP("Setting policy of chain %s to %s\n", chain, policy); - if (!cb->ops->set_policy(chain, policy, &count, - handle)) + if (!cb->ops->set_policy(chain, policy, + counters ? &count : NULL, + handle)) xtables_error(OTHER_PROBLEM, "Can't set policy `%s' on `%s' line %u: %s", policy, chain, line, diff --git a/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0 b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0 index 5ac70682..854768c9 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0 @@ -20,3 +20,10 @@ EXPECT=":foo - [0:0] $XT_MULTI iptables-restore --counters <<< "$DUMP" diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save --counters | grep foo) + +# if present, counters must be in proper format +! $XT_MULTI iptables-restore <program_name, line); if (nft_chain_builtin_find(state->curtable, chain)) { - if (counters) { - char *ctrs; - ctrs = strtok(NULL, " \t\n"); + char *ctrs = strtok(NULL, " \t\n"); - if (!ctrs || !parse_counters(ctrs, &count)) - xtables_error(PARAMETER_PROBLEM, - "invalid policy counters for chain '%s'", - chain); - - } + if ((!ctrs && counters) || + (ctrs && !parse_counters(ctrs, &count))) + xtables_error(PARAMETER_PROBLEM, + "invalid policy counters for chain '%s'", + chain); if (cb->chain_set && cb->chain_set(h, state->curtable->name, - chain, policy, &count) < 0) { + chain, policy, + counters ? &count : NULL) < 0) { xtables_error(OTHER_PROBLEM, "Can't set policy `%s' on `%s' line %u: %s", policy, chain, line, -- cgit v1.2.3 From 344e9b260ba2bbbdd0c32f112273fd552d0b73f4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Jul 2023 20:14:09 +0200 Subject: *tables: Reject invalid chain names when renaming While given chain name was sanity checked with --new-chain command, --rename-chain command allowed to choose an invalid name. Keep things consistent by adding the missing check. Fixes: e6869a8f59d77 ("reorganized tree after kernel merge") Signed-off-by: Phil Sutter --- iptables/xshared.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iptables/xshared.c b/iptables/xshared.c index 28c65fae..5f75a0a5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1511,6 +1511,7 @@ void do_parse(int argc, char *argv[], "-%c requires old-chain-name and " "new-chain-name", cmd2char(CMD_RENAME_CHAIN)); + assert_valid_chain_name(p->newname); break; case 'P': -- cgit v1.2.3 From 687d76937be799a405e63e58861f7e4a965dfa8d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Jul 2023 13:50:11 +0200 Subject: ebtables: Improve invalid chain name detection Fix several issues: - Most importantly, --new-chain command accepted any name. Introduce ebt_assert_valid_chain_name() for use with both --new-chain and --rename-chain. - Restrict maximum name length to what legacy ebtables allows - this is a bit more than iptables-nft, subject to be unified. - Like iptables, legacy ebtables rejects names prefixed by '-' or '!'. - Use xs_has_arg() for consistency, keep the check for extra args for now. Fixes: da871de2a6efb ("nft: bootstrap ebtables-compat") Signed-off-by: Phil Sutter --- iptables/xtables-eb.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index bf35f52b..08eec79d 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -42,6 +42,10 @@ #include "nft.h" #include "nft-bridge.h" +/* from linux/netfilter_bridge/ebtables.h */ +#define EBT_TABLE_MAXNAMELEN 32 +#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN + /* * From include/ebtables_u.h */ @@ -74,6 +78,26 @@ static int ebt_check_inverse2(const char option[], int argc, char **argv) return ebt_invert; } +/* XXX: merge with assert_valid_chain_name()? */ +static void ebt_assert_valid_chain_name(const char *chainname) +{ + if (strlen(chainname) >= EBT_CHAIN_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, + "Chain name length can't exceed %d", + EBT_CHAIN_MAXNAMELEN - 1); + + if (*chainname == '-' || *chainname == '!') + xtables_error(PARAMETER_PROBLEM, "No chain name specified"); + + if (xtables_find_target(chainname, XTF_TRY_LOAD)) + xtables_error(PARAMETER_PROBLEM, + "Target with name %s exists", chainname); + + if (strchr(chainname, ' ') != NULL) + xtables_error(PARAMETER_PROBLEM, + "Use of ' ' not allowed in chain names"); +} + /* * Glue code to use libxtables */ @@ -751,6 +775,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, flags |= OPT_COMMAND; if (c == 'N') { + ebt_assert_valid_chain_name(chain); ret = nft_cmd_chain_user_add(h, chain, *table); break; } else if (c == 'X') { @@ -764,14 +789,12 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, } if (c == 'E') { - if (optind >= argc) + if (!xs_has_arg(argc, argv)) xtables_error(PARAMETER_PROBLEM, "No new chain name specified"); else if (optind < argc - 1) xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E"); - else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1); - else if (strchr(argv[optind], ' ') != NULL) - xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names"); + + ebt_assert_valid_chain_name(argv[optind]); errno = 0; ret = nft_cmd_chain_user_rename(h, chain, *table, -- cgit v1.2.3 From 3bbf5269f25d7bc8cb6ecf2c44e6358579acc459 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 28 Jul 2023 13:58:46 +0200 Subject: tests: shell: Fix and extend chain rename test The old version exited unintentionally before testing ip6tables. Replace it by a more complete variant testing for all tools, creating and renaming of,chains with various illegal names instead of just renaming to a clashing name. Fixes: ed9cfe1b48526 ("tests: add initial save/restore test cases") Signed-off-by: Phil Sutter --- iptables/tests/shell/testcases/chain/0003rename_0 | 40 +++++++++++++++++++++++ iptables/tests/shell/testcases/chain/0003rename_1 | 12 ------- 2 files changed, 40 insertions(+), 12 deletions(-) create mode 100755 iptables/tests/shell/testcases/chain/0003rename_0 delete mode 100755 iptables/tests/shell/testcases/chain/0003rename_1 diff --git a/iptables/tests/shell/testcases/chain/0003rename_0 b/iptables/tests/shell/testcases/chain/0003rename_0 new file mode 100755 index 00000000..4cb2745b --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0003rename_0 @@ -0,0 +1,40 @@ +#!/bin/bash -x + +die() { + echo "E: $@" + exit 1 +} + +cmds="iptables ip6tables" +[[ $XT_MULTI == *xtables-nft-multi ]] && cmds+=" arptables ebtables" + +declare -A invnames +invnames["existing"]="c2" +invnames["spaced"]="foo bar" +invnames["dashed"]="-foo" +invnames["negated"]="!foo" +# XXX: ebtables-nft accepts 255 chars +#invnames["overlong"]="thisisquitealongnameforachain" +invnames["standard target"]="ACCEPT" +invnames["extension target"]="DNAT" + +for cmd in $cmds; do + $XT_MULTI $cmd -N c1 || die "$cmd: can't add chain c1" + $XT_MULTI $cmd -N c2 || die "$cmd: can't add chain c2" + for key in "${!invnames[@]}"; do + val="${invnames[$key]}" + if [[ $key == "extension target" ]]; then + if [[ $cmd == "arptables" ]]; then + val="mangle" + elif [[ $cmd == "ebtables" ]]; then + val="dnat" + fi + fi + $XT_MULTI $cmd -N "$val" && \ + die "$cmd: added chain with $key name" + $XT_MULTI $cmd -E c1 "$val" && \ + die "$cmd: renamed to $key name" + done +done + +exit 0 diff --git a/iptables/tests/shell/testcases/chain/0003rename_1 b/iptables/tests/shell/testcases/chain/0003rename_1 deleted file mode 100755 index 975c8e19..00000000 --- a/iptables/tests/shell/testcases/chain/0003rename_1 +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -$XT_MULTI iptables -N c1 || exit 0 -$XT_MULTI iptables -N c2 || exit 0 -$XT_MULTI iptables -E c1 c2 || exit 1 - -$XT_MULTI ip6tables -N c1 || exit 0 -$XT_MULTI ip6tables -N c2 || exit 0 -$XT_MULTI ip6tables -E c1 c2 || exit 1 - -echo "E: Renamed with existing chain" >&2 -exit 0 -- cgit v1.2.3 From 4d9453233538200e9663c6bd0c2df09e1671b5f4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 13 Jul 2023 18:32:02 +0200 Subject: iptables-restore: Drop dead code Handle initialization is guarded by 'in_table' boolean, so there can't be a handle already (because the branch which unsets 'in_table' also frees the handle). Signed-off-by: Phil Sutter --- iptables/iptables-restore.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index f11b2dc2..53029738 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -223,8 +223,6 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, } continue; } - if (handle) - cb->ops->free(handle); handle = create_handle(cb, table); if (noflush == 0) { -- cgit v1.2.3 From 9f98550d58a49fc95d529ebdc0173579d957b425 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Aug 2023 16:56:42 +0200 Subject: iptables-apply: Eliminate shellcheck warnings Actual warnings were only about use of '-a' in bracket expressions (replace by '&&' pipeline) and the immediate evaluation of the variable in trap command. The remaining changes silence info-level messages: missing quoting around variables, pointless '$' in arithmetic expressions, backticks instead of $(...), missing '-r' parameter when calling read and an awkward negated '-z' check. Signed-off-by: Phil Sutter --- iptables/iptables-apply | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iptables/iptables-apply b/iptables/iptables-apply index 3a7df5e3..c603fb21 100755 --- a/iptables/iptables-apply +++ b/iptables/iptables-apply @@ -141,9 +141,9 @@ for opt in $OPTS; do ;; (*) case "${OPT_STATE:-}" in - (SET_TIMEOUT) eval TIMEOUT=$opt;; + (SET_TIMEOUT) eval TIMEOUT="$opt";; (SET_SAVEFILE) - eval SAVEFILE=$opt + eval SAVEFILE="$opt" [ -z "$SAVEFILE" ] && SAVEFILE="$DEF_SAVEFILE" ;; esac @@ -163,13 +163,13 @@ done # Validate parameters if [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then - TIMEOUT=$(($TIMEOUT)) + TIMEOUT=$((TIMEOUT)) else echo "Error: timeout must be a positive number" >&2 exit 1 fi -if [ -n "$SAVEFILE" -a -e "$SAVEFILE" -a ! -w "$SAVEFILE" ]; then +if [ -n "$SAVEFILE" ] && [ -e "$SAVEFILE" ] && [ ! -w "$SAVEFILE" ]; then echo "Error: savefile not writable: $SAVEFILE" >&2 exit 8 fi @@ -205,8 +205,8 @@ esac ### Begin work # Store old iptables rules to temporary file -TMPFILE=`mktemp /tmp/$PROGNAME-XXXXXXXX` -trap "rm -f $TMPFILE" EXIT HUP INT QUIT ILL TRAP ABRT BUS \ +TMPFILE=$(mktemp "/tmp/$PROGNAME-XXXXXXXX") +trap 'rm -f $TMPFILE' EXIT HUP INT QUIT ILL TRAP ABRT BUS \ FPE USR1 SEGV USR2 PIPE ALRM TERM if ! "$SAVE" >"$TMPFILE"; then @@ -257,13 +257,13 @@ esac # Prompt user for confirmation echo -n "Can you establish NEW connections to the machine? (y/N) " -read -n1 -t "$TIMEOUT" ret 2>&1 || : +read -r -n1 -t "$TIMEOUT" ret 2>&1 || : case "${ret:-}" in (y*|Y*) # Success echo - if [ ! -z "$SAVEFILE" ]; then + if [ -n "$SAVEFILE" ]; then # Write successfully applied rules to the savefile echo "Writing successfully applied rules to '$SAVEFILE'..." if ! "$SAVE" >"$SAVEFILE"; then -- cgit v1.2.3 From 5b5430d627bbc227a2d51d4312c371f2015834c6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Aug 2023 23:28:20 +0200 Subject: extensions: libipt_icmp: Fix confusion between 255/255 and any Per definition, ICMP type "any" is type 255 and the full range of codes (0-255). Save callback though ignored the actual code values, printing "any" for every type 255 match. This at least confuses users as they can't find their rule added as '--icmp-type 255/255' anymore. It is not entirely clear what the fixed commit was trying to establish, but the save output is certainly not correct (especially since print callback gets things right). Reported-by: Amelia Downs Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1600 Fixes: fc9237da4e845 ("Fix '-p icmp -m icmp' issue (Closes: #37)") Signed-off-by: Phil Sutter --- extensions/libipt_icmp.c | 3 ++- extensions/libipt_icmp.t | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index b0318aeb..171b3b39 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -108,7 +108,8 @@ static void icmp_save(const void *ip, const struct xt_entry_match *match) printf(" !"); /* special hack for 'any' case */ - if (icmp->type == 0xFF) { + if (icmp->type == 0xFF && + icmp->code[0] == 0 && icmp->code[1] == 0xFF) { printf(" --icmp-type any"); } else { printf(" --icmp-type %u", icmp->type); diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t index f4ba65c2..ce4a33f9 100644 --- a/extensions/libipt_icmp.t +++ b/extensions/libipt_icmp.t @@ -13,3 +13,5 @@ # we accept "iptables -I INPUT -p tcp -m tcp", why not this below? # ERROR: cannot load: iptables -A INPUT -p icmp -m icmp # -p icmp -m icmp;=;OK +-p icmp -m icmp --icmp-type 255/255;=;OK +-p icmp -m icmp --icmp-type 255/0:255;-p icmp -m icmp --icmp-type any;OK -- cgit v1.2.3 From 99d861c64cda5289e141b2084836663450f1eff0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Aug 2023 23:42:24 +0200 Subject: tests: libipt_icmp.t: Enable tests with numeric output Unrelated to the question whether numeric (save) output is desired or not, enable the tests and expect the known format. Using --list without --numeric prints the names, BTW. Fixes: 49d5b7277c7f2 ("extensions: libipt_icmp: add unit test") Signed-off-by: Phil Sutter --- extensions/libipt_icmp.t | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t index ce4a33f9..4ea93621 100644 --- a/extensions/libipt_icmp.t +++ b/extensions/libipt_icmp.t @@ -1,11 +1,8 @@ :INPUT,FORWARD,OUTPUT -p icmp -m icmp --icmp-type any;=;OK -# output uses the number, better use the name? -# ERROR: cannot find: iptables -I INPUT -p icmp -m icmp --icmp-type echo-reply -# -p icmp -m icmp --icmp-type echo-reply;=;OK -# output uses the number, better use the name? -# ERROR: annot find: iptables -I INPUT -p icmp -m icmp --icmp-type destination-unreachable -# -p icmp -m icmp --icmp-type destination-unreachable;=;OK +# XXX: output uses the number, better use the name? +-p icmp -m icmp --icmp-type echo-reply;-p icmp -m icmp --icmp-type 0;OK +-p icmp -m icmp --icmp-type destination-unreachable;-p icmp -m icmp --icmp-type 3;OK # it does not acccept name/name, should we accept this? # ERROR: cannot load: iptables -A INPUT -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable # -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable;=;OK -- cgit v1.2.3 From 13c9efa80e50bdf9187b5f5a16b34eda49425fd3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 1 Aug 2023 21:24:15 +0200 Subject: man: iptables.8: Extend exit code description Codes 3 and 4 were missing. Reported-by: Steven Barre Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1353 Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index f81c632f..2dd14066 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -410,9 +410,12 @@ the default setting. iptables can use extended packet matching and target modules. A list of these is available in the \fBiptables\-extensions\fP(8) manpage. .SH DIAGNOSTICS -Various error messages are printed to standard error. The exit code -is 0 for correct functioning. Errors which appear to be caused by -invalid or abused command line parameters cause an exit code of 2, and +Various error messages are printed to standard error. The exit code is 0 for +correct functioning. Errors which appear to be caused by invalid or abused +command line parameters cause an exit code of 2. Errors which indicate an +incompatibility between kernel and user space cause an exit code of 3. Errors +which indicate a resource problem, such as a busy lock, failing memory +allocation or error messages from kernel cause an exit code of 4. Finally, other errors cause an exit code of 1. .SH BUGS Bugs? What's this? ;-) -- cgit v1.2.3 From fae244f731b0198ec0194903e7e82944efd9bfa3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 00:05:45 +0200 Subject: man: iptables.8: Trivial spelling fixes - Missing "and" as well as full stop - Missing comma in enumeration - Duplicate "previous" - Confusions are avoided rather than simplified - Missing space after comma Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 2dd14066..6486588e 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -125,8 +125,8 @@ This table is used mainly for configuring exemptions from connection tracking in combination with the NOTRACK target. It registers at the netfilter hooks with higher priority and is thus called before ip_conntrack, or any other IP tables. It provides the following built-in chains: \fBPREROUTING\fP -(for packets arriving via any network interface) \fBOUTPUT\fP -(for packets generated by local processes) +(for packets arriving via any network interface) and \fBOUTPUT\fP +(for packets generated by local processes). .TP \fBsecurity\fP: This table is used for Mandatory Access Control (MAC) networking rules, such @@ -258,7 +258,7 @@ This option has no effect in ip6tables and ip6tables-restore. [\fB!\fP] \fB\-p\fP, \fB\-\-protocol\fP \fIprotocol\fP The protocol of the rule or of the packet to check. The specified protocol can be one of \fBtcp\fP, \fBudp\fP, \fBudplite\fP, -\fBicmp\fP, \fBicmpv6\fP,\fBesp\fP, \fBah\fP, \fBsctp\fP, \fBmh\fP or the special keyword "\fBall\fP", +\fBicmp\fP, \fBicmpv6\fP, \fBesp\fP, \fBah\fP, \fBsctp\fP, \fBmh\fP or the special keyword "\fBall\fP", or it can be a numeric value, representing one of these protocols or a different one. A protocol name from /etc/protocols is also allowed. A "!" argument before the protocol inverts the @@ -386,7 +386,7 @@ network names, or services (whenever applicable). \fB\-x\fP, \fB\-\-exact\fP Expand numbers. Display the exact value of the packet and byte counters, -instead of only the rounded number in K's (multiples of 1000) +instead of only the rounded number in K's (multiples of 1000), M's (multiples of 1000K) or G's (multiples of 1000M). This option is only relevant for the \fB\-L\fP command. .TP @@ -441,7 +441,7 @@ entering the \fBFORWARD\fP chain. .PP The various forms of NAT have been separated out; \fBiptables\fP is a pure packet filter when using the default `filter' table, with -optional extension modules. This should simplify much of the previous +optional extension modules. This should avoid much of the confusion over the combination of IP masquerading and packet filtering seen previously. So the following options are handled differently: .nf -- cgit v1.2.3 From 3bda308b32847d08b2c27077fa3c02200b59cdca Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 00:23:37 +0200 Subject: man: iptables.8: Fix intra page reference When sections MATCH EXTENSIONS and TARGET EXTENSIONS were combined, the reference could have been updated to specify the exact title. Fixes: 4496801821c01 ("doc: deduplicate extension descriptions into a new manpage") Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 6486588e..85af1800 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -307,8 +307,8 @@ false, evaluation will stop. This specifies the target of the rule; i.e., what to do if the packet matches it. The target can be a user-defined chain (other than the one this rule is in), one of the special builtin targets which decide -the fate of the packet immediately, or an extension (see \fBEXTENSIONS\fP -below). If this +the fate of the packet immediately, or an extension (see \fBMATCH AND TARGET +EXTENSIONS\fP below). If this option is omitted in a rule (and \fB\-g\fP is not used), then matching the rule will have no effect on the packet's fate, but the counters on the rule will be -- cgit v1.2.3 From 94c19939744dbbbc6ff0fedf6cdba661769fdc87 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 00:28:03 +0200 Subject: man: iptables.8: Clarify --goto description Text speaks about behaviour of RETURN target when used in chains redirected to using --goto instead of --jump, not the difference between --jump option and "return". Fixes: 17fc163babc34 ("add 'goto' support (Henrik Nordstrom )") Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 85af1800..c83275b2 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -316,7 +316,7 @@ incremented. .TP \fB\-g\fP, \fB\-\-goto\fP \fIchain\fP This specifies that the processing should continue in a user -specified chain. Unlike the \-\-jump option return will not continue +specified chain. Unlike with the \-\-jump option, \fBRETURN\fP will not continue processing in this chain but instead in the chain that called us via \-\-jump. .TP -- cgit v1.2.3 From a41ec065ebad9b38ebf2a193aeb42f59a7e30214 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 00:41:38 +0200 Subject: man: Use HTTPS for links to netfilter.org The browser is redirected there anyway, but who cares about such minor details nowadays. Signed-off-by: Phil Sutter --- extensions/libxt_nfacct.man | 2 +- iptables/iptables.8.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/libxt_nfacct.man b/extensions/libxt_nfacct.man index b755f977..a818fedd 100644 --- a/extensions/libxt_nfacct.man +++ b/extensions/libxt_nfacct.man @@ -26,5 +26,5 @@ nfacct get http\-traffic .PP You can obtain .B nfacct(8) -from http://www.netfilter.org or, alternatively, from the git.netfilter.org +from https://www.netfilter.org or, alternatively, from the git.netfilter.org repository. diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index c83275b2..71a6251d 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -419,7 +419,7 @@ allocation or error messages from kernel cause an exit code of 4. Finally, other errors cause an exit code of 1. .SH BUGS Bugs? What's this? ;-) -Well, you might want to have a look at http://bugzilla.netfilter.org/ +Well, you might want to have a look at https://bugzilla.netfilter.org/ \fBiptables\fP will exit immediately with an error code of 111 if it finds that it was called as a setuid-to-root program. iptables cannot be used safely in this manner because it trusts @@ -463,7 +463,7 @@ not in the standard distribution, and the netfilter-hacking-HOWTO details the netfilter internals. .br See -.BR "http://www.netfilter.org/" . +.BR "https://www.netfilter.org/" . .SH AUTHORS Rusty Russell originally wrote iptables, in early consultation with Michael Neuling. -- cgit v1.2.3 From beaed986f772dfd31cbfc58daadc97b886a786b2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 00:49:03 +0200 Subject: man: iptables.8: Trivial font fixes No content changes intended, just type commands in bold and the single path reference in italics. Signed-off-by: Phil Sutter --- iptables/iptables.8.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 71a6251d..ecaa5553 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -244,13 +244,13 @@ add, delete, insert, replace and append commands). \fB\-4\fP, \fB\-\-ipv4\fP This option has no effect in iptables and iptables-restore. If a rule using the \fB\-4\fP option is inserted with (and only with) -ip6tables-restore, it will be silently ignored. Any other uses will throw an +\fBip6tables\-restore\fP, it will be silently ignored. Any other uses will throw an error. This option allows IPv4 and IPv6 rules in a single rule file for use with both iptables-restore and ip6tables-restore. .TP \fB\-6\fP, \fB\-\-ipv6\fP If a rule using the \fB\-6\fP option is inserted with (and only with) -iptables-restore, it will be silently ignored. Any other uses will throw an +\fBiptables\-restore\fP, it will be silently ignored. Any other uses will throw an error. This option allows IPv4 and IPv6 rules in a single rule file for use with both iptables-restore and ip6tables-restore. This option has no effect in ip6tables and ip6tables-restore. @@ -260,7 +260,7 @@ The protocol of the rule or of the packet to check. The specified protocol can be one of \fBtcp\fP, \fBudp\fP, \fBudplite\fP, \fBicmp\fP, \fBicmpv6\fP, \fBesp\fP, \fBah\fP, \fBsctp\fP, \fBmh\fP or the special keyword "\fBall\fP", or it can be a numeric value, representing one of these protocols or a -different one. A protocol name from /etc/protocols is also allowed. +different one. A protocol name from \fI/etc/protocols\fP is also allowed. A "!" argument before the protocol inverts the test. The number zero is equivalent to \fBall\fP. "\fBall\fP" will match with all protocols and is taken as default when this -- cgit v1.2.3 From 0f05f523ac02843ab7bbd09a96ba3fa384ae9523 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:27:11 +0200 Subject: man: iptables-restore.8: Fix --modprobe description - Consistently use 'modprobe' as option argument name - Add a reference to modprobe man page - Put the path in italics, and the command in bold Fixes: 8c46901ff5785 ("doc: document iptables-restore's -M option") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index 20216842..f95f00ac 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -67,9 +67,10 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP -\fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP -Specify the path to the modprobe program. By default, iptables-restore will -inspect /proc/sys/kernel/modprobe to determine the executable's path. +\fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe\fP +Specify the path to the modprobe(8) program. By default, +iptables-restore will inspect \fI/proc/sys/kernel/modprobe\fP to +determine the executable's path. .TP \fB\-T\fP, \fB\-\-table\fP \fIname\fP Restore only the named table even if the input stream contains other ones. -- cgit v1.2.3 From e7bc6cc8aca993b743e83f20b2f579aed2f5d954 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:33:26 +0200 Subject: man: iptables-restore.8: Consistently document -w option Use the same name for the option's argument. Fixes: 65801d02a482b ("iptables-restore.8: document -w/-W options") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index f95f00ac..a63a344c 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -23,11 +23,11 @@ iptables-restore \(em Restore IP Tables .P ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS -\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP] +\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fBfile\fP] .P -\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP] +\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fBfile\fP] .SH DESCRIPTION -- cgit v1.2.3 From 193107df55541ced2e783bcce9b71b97f88a5398 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:34:51 +0200 Subject: man: iptables-restore.8: Drop -W option from synopsis The description was dropped already, there is no benefit in still listing it. Fixes: 07e2107ef0cbc ("xshared: Implement xtables lock timeout using signals") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index a63a344c..bfd2fc35 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -24,11 +24,11 @@ iptables-restore \(em Restore IP Tables ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS \fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] -[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] +[\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fBfile\fP] .P \fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] -[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] +[\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fBfile\fP] .SH DESCRIPTION .PP -- cgit v1.2.3 From b200f0870bc17046d6db64a1a65937ad5f263633 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:37:09 +0200 Subject: man: iptables-restore.8: Put 'file' in italics in synopsis The text has it this way already, be consistent. Fixes: 081d57839e91e ("iptables-restore.8: file to read from can be specified as argument") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index bfd2fc35..ff817909 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -25,11 +25,11 @@ ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS \fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] -[\fBfile\fP] +[\fIfile\fP] .P \fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] -[\fBfile\fP] +[\fIfile\fP] .SH DESCRIPTION .PP .B iptables-restore -- cgit v1.2.3 From 935a5cf8afa96daa1c688efd59b9025e3a78fba4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:40:17 +0200 Subject: man: iptables-restore.8: Start paragraphs in upper-case Also add a missing full stop in one spot. Fixes: 117341ada43dd ("Added iptbles-restore and iptables-save manpages") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index ff817909..ce4520e6 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -40,13 +40,13 @@ are used to restore IP and IPv6 Tables from data specified on STDIN or in specify \fIfile\fP as an argument. .TP \fB\-c\fR, \fB\-\-counters\fR -restore the values of all packet and byte counters +Restore the values of all packet and byte counters. .TP \fB\-h\fP, \fB\-\-help\fP Print a short option summary. .TP \fB\-n\fR, \fB\-\-noflush\fR -don't flush the previous contents of the table. If not specified, +Don't flush the previous contents of the table. If not specified, both commands flush (delete) all previous contents of the respective table. .TP \fB\-t\fP, \fB\-\-test\fP -- cgit v1.2.3 From b0092a80656da7cf66f15ce906b17ab040ece12f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:48:14 +0200 Subject: man: Trivial: Missing space after comma Fixes: 6a79d78986c02 ("iptables: mention iptables-apply(8) in manpages") Signed-off-by: Phil Sutter --- iptables/iptables-restore.8.in | 2 +- iptables/iptables-save.8.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index ce4520e6..aa816f79 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -82,7 +82,7 @@ from Rusty Russell. .br Andras Kis-Szabo contributed ip6tables-restore. .SH SEE ALSO -\fBiptables\-apply\fP(8),\fBiptables\-save\fP(8), \fBiptables\fP(8) +\fBiptables\-apply\fP(8), \fBiptables\-save\fP(8), \fBiptables\fP(8) .PP The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO, which details NAT, and the netfilter-hacking-HOWTO which details the diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 7683fd37..25390771 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -62,7 +62,7 @@ Rusty Russell .br Andras Kis-Szabo contributed ip6tables-save. .SH SEE ALSO -\fBiptables\-apply\fP(8),\fBiptables\-restore\fP(8), \fBiptables\fP(8) +\fBiptables\-apply\fP(8), \fBiptables\-restore\fP(8), \fBiptables\fP(8) .PP The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO, which details NAT, and the netfilter-hacking-HOWTO which details the -- cgit v1.2.3 From 9458313e017eaa0f8daccff57df24da01f5b6fb8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 01:55:08 +0200 Subject: man: iptables-save.8: Clarify 'available tables' This appears to be confusing. Since a missing table is also not flushed ("restored") when feeding the dump into iptables-restore, such a restore call may be considered incomplete. Signed-off-by: Phil Sutter --- iptables/iptables-save.8.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 25390771..7f849073 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -52,7 +52,10 @@ 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. +If not specified, output includes all available tables. No module loading takes +place, so in order to include a specific table in the output, the respective +module (something like \fBiptable_mangle\fP or \fBip6table_raw\fP) must be +loaded first. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHORS -- cgit v1.2.3 From f1fd95ccefe483f0e3f2da593c6d4b671a7de522 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 02:01:59 +0200 Subject: man: iptables-save.8: Fix --modprobe description - Consistently use 'modprobe' as option argument name - Add a reference to modprobe man page - Put the path in italics and the command in bold Fixes: fbb5639c02218 ("iptables-save: module loading corrections") Signed-off-by: Phil Sutter --- iptables/iptables-save.8.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 7f849073..118dddcd 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -36,9 +36,10 @@ and are used to dump the contents of IP or IPv6 Table in easily parseable format either to STDOUT or to a specified file. .TP -\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP -Specify the path to the modprobe program. By default, iptables-save will -inspect /proc/sys/kernel/modprobe to determine the executable's path. +\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe\fP +Specify the path to the modprobe(8) program. By default, +iptables-save will inspect \fI/proc/sys/kernel/modprobe\fP to determine +the executable's path. .TP \fB\-f\fR, \fB\-\-file\fR \fIfilename\fP Specify a filename to log the output to. If not specified, iptables-save -- cgit v1.2.3 From 952186aa0342f6bf3c4614a609525338d057d8d9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 02:06:00 +0200 Subject: man: iptables-save.8: Start paragraphs in upper-case Also add a missing full stop. Fixes: 117341ada43dd ("Added iptbles-restore and iptables-save manpages") Signed-off-by: Phil Sutter --- iptables/iptables-save.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 118dddcd..65c1f28c 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -46,10 +46,10 @@ Specify a filename to log the output to. If not specified, iptables-save will log to STDOUT. .TP \fB\-c\fR, \fB\-\-counters\fR -include the current values of all packet and byte counters in the output +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 the kernel is configured with automatic +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 -- cgit v1.2.3 From d5c869add2501aa722682c825b7b9ee247d22ec8 Mon Sep 17 00:00:00 2001 From: Jan Palus Date: Mon, 28 Dec 2020 10:59:42 +0100 Subject: nft: move processing logic out of asserts [Phil: Introduce assert_nft_restart() to keep things clean, also add fallback returns to nft_action() and nft_prepare(), sanitizing things at least a bit.] Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1487 Signed-off-by: Jan Palus Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 16 ++++++++++++---- iptables/nft.c | 7 +++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index fabb5779..91d29670 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -26,6 +26,14 @@ #include "nft-cache.h" #include "nft-chain.h" +/* users may define NDEBUG */ +static void assert_nft_restart(struct nft_handle *h) +{ + int rc = nft_restart(h); + + assert(rc >= 0); +} + static void cache_chain_list_insert(struct list_head *list, const char *name) { struct cache_chain *pos = NULL, *new; @@ -147,7 +155,7 @@ static int fetch_table_cache(struct nft_handle *h) ret = mnl_talk(h, nlh, nftnl_table_list_cb, h); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); for (i = 0; i < NFT_TABLE_MAX; i++) { enum nft_table_type type = h->tables[i].type; @@ -472,7 +480,7 @@ static int fetch_set_cache(struct nft_handle *h, ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d); if (ret < 0 && errno == EINTR) { - assert(nft_restart(h) >= 0); + assert_nft_restart(h); return ret; } @@ -512,7 +520,7 @@ static int __fetch_chain_cache(struct nft_handle *h, ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); return ret; } @@ -606,7 +614,7 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); nftnl_rule_free(rule); diff --git a/iptables/nft.c b/iptables/nft.c index b702c65a..326dc20b 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -109,7 +109,9 @@ static struct nftnl_batch *mnl_batch_init(void) static void mnl_nft_batch_continue(struct nftnl_batch *batch) { - assert(nftnl_batch_update(batch) >= 0); + int ret = nftnl_batch_update(batch); + + assert(ret >= 0); } static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum) @@ -3227,6 +3229,7 @@ retry: case NFT_COMPAT_RULE_ZERO: case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: assert(0); + return 0; } mnl_nft_batch_continue(h->batch); @@ -3504,7 +3507,7 @@ static int nft_prepare(struct nft_handle *h) case NFT_COMPAT_TABLE_ADD: case NFT_COMPAT_CHAIN_ADD: assert(0); - break; + return 0; } nft_cmd_free(cmd); -- cgit v1.2.3 From bb7d5fde80ccb4672dcf9644b4ccf1bffc0919fd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Aug 2023 11:31:56 +0200 Subject: extensions: libip6t_icmp: Add names for mld-listener types Add the three names (plus one alias) just as in nftables. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1250 Signed-off-by: Phil Sutter --- extensions/libip6t_icmp6.t | 4 ++++ extensions/libxt_icmp.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/extensions/libip6t_icmp6.t b/extensions/libip6t_icmp6.t index 028cfc16..b9a4dcd3 100644 --- a/extensions/libip6t_icmp6.t +++ b/extensions/libip6t_icmp6.t @@ -4,3 +4,7 @@ -p ipv6-icmp -m icmp6 --icmpv6-type 2;=;OK # cannot use option twice: -p ipv6-icmp -m icmp6 --icmpv6-type no-route --icmpv6-type packet-too-big;;FAIL +-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-query;-p ipv6-icmp -m icmp6 --icmpv6-type 130;OK +-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-report;-p ipv6-icmp -m icmp6 --icmpv6-type 131;OK +-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-done;-p ipv6-icmp -m icmp6 --icmpv6-type 132;OK +-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-reduction;-p ipv6-icmp -m icmp6 --icmpv6-type 132;OK diff --git a/extensions/libxt_icmp.h b/extensions/libxt_icmp.h index a763e50c..7a45b4bd 100644 --- a/extensions/libxt_icmp.h +++ b/extensions/libxt_icmp.h @@ -83,6 +83,13 @@ static const struct xt_icmp_names { { "echo-reply", 129, 0, 0xFF }, /* Alias */ { "pong", 129, 0, 0xFF }, + { "mld-listener-query", 130, 0, 0xFF }, + + { "mld-listener-report", 131, 0, 0xFF }, + + { "mld-listener-done", 132, 0, 0xFF }, + /* Alias */ { "mld-listener-reduction", 132, 0, 0xFF }, + { "router-solicitation", 133, 0, 0xFF }, { "router-advertisement", 134, 0, 0xFF }, -- cgit v1.2.3 From 2a6eee89083c837ac429b0e5aba33bdcaeb51a57 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 31 Jan 2023 19:55:57 +0100 Subject: nft-ruleparse: Introduce nft_create_target() Like nft_create_match(), this is a small wrapper around the typical target extension lookup and (standard) init code. To use it from nft_parse_target() and nft_parse_log(), introduce an inner variant which accepts the target payload size as parameter. The call to rule_parse_ops::target callback was problematic with standard target, because the callbacks initialized iptables_command_state::jumpto with the target name, "standard" in that case. Perform its tasks in nft_create_target(), keep it only for bridge family's special handling of watcher "targets". Signed-off-by: Phil Sutter --- iptables/nft-ruleparse-arp.c | 1 - iptables/nft-ruleparse-bridge.c | 5 +- iptables/nft-ruleparse-ipv4.c | 1 - iptables/nft-ruleparse-ipv6.c | 1 - iptables/nft-ruleparse.c | 126 +++++++++++++++------------------------- iptables/nft-ruleparse.h | 5 +- 6 files changed, 52 insertions(+), 87 deletions(-) diff --git a/iptables/nft-ruleparse-arp.c b/iptables/nft-ruleparse-arp.c index b68fb06d..d80ca922 100644 --- a/iptables/nft-ruleparse-arp.c +++ b/iptables/nft-ruleparse-arp.c @@ -164,5 +164,4 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, struct nft_ruleparse_ops nft_ruleparse_ops_arp = { .meta = nft_arp_parse_meta, .payload = nft_arp_parse_payload, - .target = nft_ipv46_parse_target, }; diff --git a/iptables/nft-ruleparse-bridge.c b/iptables/nft-ruleparse-bridge.c index 50fb9283..c6cc9af5 100644 --- a/iptables/nft-ruleparse-bridge.c +++ b/iptables/nft-ruleparse-bridge.c @@ -406,11 +406,10 @@ static void nft_bridge_parse_target(struct xtables_target *t, if (strcmp(t->name, "log") == 0 || strcmp(t->name, "nflog") == 0) { parse_watcher(t, &cs->match_list, false); + cs->jumpto = NULL; + cs->target = NULL; return; } - - cs->target = t; - cs->jumpto = t->name; } struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { diff --git a/iptables/nft-ruleparse-ipv4.c b/iptables/nft-ruleparse-ipv4.c index c87e159c..491cbf42 100644 --- a/iptables/nft-ruleparse-ipv4.c +++ b/iptables/nft-ruleparse-ipv4.c @@ -131,5 +131,4 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = { .meta = nft_ipv4_parse_meta, .payload = nft_ipv4_parse_payload, - .target = nft_ipv46_parse_target, }; diff --git a/iptables/nft-ruleparse-ipv6.c b/iptables/nft-ruleparse-ipv6.c index af55420b..7581b863 100644 --- a/iptables/nft-ruleparse-ipv6.c +++ b/iptables/nft-ruleparse-ipv6.c @@ -108,5 +108,4 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = { .meta = nft_ipv6_parse_meta, .payload = nft_ipv6_parse_payload, - .target = nft_ipv46_parse_target, }; diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c index edbbfa40..a5eb6d09 100644 --- a/iptables/nft-ruleparse.c +++ b/iptables/nft-ruleparse.c @@ -84,6 +84,40 @@ nft_create_match(struct nft_xt_ctx *ctx, return match->m->data; } +static void * +__nft_create_target(struct nft_xt_ctx *ctx, const char *name, size_t tgsize) +{ + struct xtables_target *target; + size_t size; + + target = xtables_find_target(name, XTF_TRY_LOAD); + if (!target) + return NULL; + + size = XT_ALIGN(sizeof(*target->t)) + tgsize ?: target->size; + + target->t = xtables_calloc(1, size); + target->t->u.target_size = size; + target->t->u.user.revision = target->revision; + strcpy(target->t->u.user.name, name); + + xs_init_target(target); + + ctx->cs->jumpto = name; + ctx->cs->target = target; + + if (ctx->h->ops->rule_parse->target) + ctx->h->ops->rule_parse->target(target, ctx->cs); + + return target->t->data; +} + +void * +nft_create_target(struct nft_xt_ctx *ctx, const char *name) +{ + return __nft_create_target(ctx, name, 0); +} + static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) { counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); @@ -123,11 +157,8 @@ static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, static void nft_parse_meta_set(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { - struct xtables_target *target; struct nft_xt_ctx_reg *sreg; enum nft_registers sregnum; - struct xt_entry_target *t; - unsigned int size; const char *targname; sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); @@ -153,22 +184,8 @@ static void nft_parse_meta_set(struct nft_xt_ctx *ctx, return; } - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) { + if (!nft_create_target(ctx, targname)) ctx->errmsg = "target TRACE not found"; - return; - } - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = target->revision; - strcpy(t->u.user.name, targname); - - target->t = t; - - ctx->h->ops->rule_parse->target(target, ctx->cs); } static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -515,8 +532,6 @@ 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 iptables_command_state *cs = ctx->cs; - struct xt_entry_target *t; - uint32_t size; int verdict; if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { @@ -566,18 +581,8 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) return; } - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - if (!cs->target) { + if (!nft_create_target(ctx, cs->jumpto)) ctx->errmsg = "verdict extension not found"; - 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; } static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -624,27 +629,13 @@ 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); const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); - struct xtables_target *target; - struct xt_entry_target *t; - size_t size; + void *data; - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) { + data = __nft_create_target(ctx, targname, tg_len); + if (!data) ctx->errmsg = "target extension not found"; - return; - } - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; - - t = xtables_calloc(1, size); - memcpy(&t->data, targinfo, tg_len); - t->u.target_size = size; - t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(t->u.user.name, target->name); - - target->t = t; - - ctx->h->ops->rule_parse->target(target, ctx->cs); + else + memcpy(data, targinfo, tg_len); } static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) @@ -684,9 +675,6 @@ static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { - struct xtables_target *target; - struct xt_entry_target *t; - size_t target_size; /* * In order to handle the longer log-prefix supported by nft, instead of * using struct xt_nflog_info, we use a struct with a compatible layout, but @@ -703,6 +691,8 @@ static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), }; + void *data; + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); info.flags = XT_NFLOG_F_COPY_LEN; @@ -711,25 +701,12 @@ static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) snprintf(info.prefix, sizeof(info.prefix), "%s", nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); - target = xtables_find_target("NFLOG", XTF_TRY_LOAD); - if (target == NULL) { + data = __nft_create_target(ctx, "NFLOG", + XT_ALIGN(sizeof(struct xt_nflog_info_nft))); + if (!data) ctx->errmsg = "NFLOG target extension not found"; - return; - } - - target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + - XT_ALIGN(sizeof(struct xt_nflog_info_nft)); - - t = xtables_calloc(1, target_size); - t->u.target_size = target_size; - strcpy(t->u.user.name, target->name); - t->u.user.revision = target->revision; - - target->t = t; - - memcpy(&target->t->data, &info, sizeof(info)); - - ctx->h->ops->rule_parse->target(target, ctx->cs); + else + memcpy(data, &info, sizeof(info)); } static void nft_parse_udp_range(struct nft_xt_ctx *ctx, @@ -1137,13 +1114,6 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, return 0; } -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - cs->target = t; - cs->jumpto = t->name; -} - int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs) { diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h index fd083c08..25ce05d2 100644 --- a/iptables/nft-ruleparse.h +++ b/iptables/nft-ruleparse.h @@ -117,6 +117,8 @@ extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv6; void *nft_create_match(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, const char *name, bool reuse); +void *nft_create_target(struct nft_xt_ctx *ctx, const char *name); + bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, @@ -129,9 +131,6 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags); -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs); - int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs); -- cgit v1.2.3 From 7304f1982d619e19860106bc74b9cf3d05ddb113 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 3 Aug 2023 21:39:13 +0200 Subject: nft-ruleparse: parse meta mark set as MARK target Mixing nftables and iptables-nft in the same table doesn't work, but some people do this. v1.8.8 ignored rules it could not represent in iptables syntax, v1.8.9 bails in this case. Add parsing of meta mark expressions so iptables-nft can render them as -j MARK rules. This is flawed, nft has features that have no corresponding syntax in iptables, but we can't undo this. Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1659 Signed-off-by: Florian Westphal Signed-off-by: Phil Sutter --- iptables/nft-ruleparse.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c index a5eb6d09..c8322f93 100644 --- a/iptables/nft-ruleparse.c +++ b/iptables/nft-ruleparse.c @@ -146,11 +146,6 @@ static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, return false; } - if (sreg->immediate.data[0] == 0) { - ctx->errmsg = "meta sreg immediate is 0"; - return false; - } - return true; } @@ -159,7 +154,6 @@ static void nft_parse_meta_set(struct nft_xt_ctx *ctx, { struct nft_xt_ctx_reg *sreg; enum nft_registers sregnum; - const char *targname; sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); sreg = nft_xt_ctx_get_sreg(ctx, sregnum); @@ -171,21 +165,43 @@ static void nft_parse_meta_set(struct nft_xt_ctx *ctx, if (!nft_parse_meta_set_common(ctx, sreg)) return; - targname = "TRACE"; + if (sreg->immediate.data[0] == 0) { + ctx->errmsg = "meta sreg immediate is 0"; + return; + } + + if (!nft_create_target(ctx, "TRACE")) + ctx->errmsg = "target TRACE not found"; break; case NFT_META_BRI_BROUTE: if (!nft_parse_meta_set_common(ctx, sreg)) return; ctx->cs->jumpto = "DROP"; - return; + break; + case NFT_META_MARK: { + struct xt_mark_tginfo2 *mt; + + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + mt = nft_create_target(ctx, "MARK"); + if (!mt) { + ctx->errmsg = "target MARK not found"; + return; + } + + mt->mark = sreg->immediate.data[0]; + if (sreg->bitwise.set) + mt->mask = sreg->bitwise.mask[0]; + else + mt->mask = ~0u; + break; + } default: ctx->errmsg = "meta sreg key not supported"; - return; + break; } - - if (!nft_create_target(ctx, targname)) - ctx->errmsg = "target TRACE not found"; } static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -- cgit v1.2.3 From 5412ccba55b2318160d32efec3b8aad162608af9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 26 Jul 2023 19:43:20 +0200 Subject: tests: iptables-test: Fix command segfault reports Logging produced a stack trace due to undefined variable 'cmd'. Fixes: 0e80cfea3762b ("tests: iptables-test: Implement fast test mode") Signed-off-by: Phil Sutter --- iptables-test.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iptables-test.py b/iptables-test.py index ef0a35d3..6f63cdbe 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -136,7 +136,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): # check for segfaults # if proc.returncode == -11: - reason = "iptables-save segfaults: " + cmd + reason = command + " segfaults!" print_error(reason, filename, lineno) delete_rule(iptables, rule, filename, lineno, netns) return -1 @@ -333,8 +333,11 @@ def run_test_file_fast(iptables, filename, netns): out, err = proc.communicate(input = restore_data) if proc.returncode == -11: - reason = iptables + "-restore segfaults: " + cmd + reason = iptables + "-restore segfaults!" print_error(reason, filename, lineno) + msg = [iptables + "-restore segfault from:"] + msg.extend(["input: " + l for l in restore_data.split("\n")]) + print("\n".join(msg), file=log_file) return -1 if proc.returncode != 0: @@ -355,7 +358,7 @@ def run_test_file_fast(iptables, filename, netns): out, err = proc.communicate() if proc.returncode == -11: - reason = iptables + "-save segfaults: " + cmd + reason = iptables + "-save segfaults!" print_error(reason, filename, lineno) return -1 -- cgit v1.2.3 From 39a067bb3b1b4ffb50a925f66e7db56658c0dfa7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 10 Aug 2023 11:30:59 +0200 Subject: nft: Create builtin chains with counters enabled The kernel enables policy counters for nftables chains only if NFTA_CHAIN_COUNTERS attribute is present. For this to be generated, one has to set NFTNL_CHAIN_PACKETS and NFTNL_CHAIN_BYTES attributes in the allocated nftnl_chain object. The above happened for base chains only with iptables-nft-restore if called with --counters flag. Since this is very unintuitive to users, fix the situation by adding counters to base chains in any case. Fixes: 384958620abab ("use nf_tables and nf_tables compatibility interface") Signed-off-by: Phil Sutter --- iptables/nft.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 326dc20b..97fd4f49 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -701,6 +701,9 @@ nft_chain_builtin_alloc(int family, const char *tname, nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type); + nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); + nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); + return c; } @@ -961,6 +964,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, int policy, const struct xt_counters *counters) { + static const struct xt_counters zero = {}; struct nftnl_chain *c; const struct builtin_table *_t; const struct builtin_chain *_c; @@ -985,12 +989,10 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, return NULL; } - if (counters) { - nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, - counters->bcnt); - nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, - counters->pcnt); - } + if (!counters) + counters = &zero; + nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, counters->bcnt); + nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, counters->pcnt); return c; } -- cgit v1.2.3 From 43f78733059ecd28d8567d8205cab5ed62d93458 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 3 Aug 2023 17:59:03 +0200 Subject: Revert "libiptc: fix wrong maptype of base chain counters on restore" This reverts commit 7c4d668c9c2ee007c82063b7fc784cbbf46b2ec4. The change can't be right: A simple rule append call will reset all built-in chains' counters. The old code works fine even given the mentioned "empty restore" use-case, at least if counters don't change on the fly in-kernel. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=912 Fixes: 7c4d668c9c2ee ("libiptc: fix wrong maptype of base chain counters on restore") Signed-off-by: Phil Sutter --- libiptc/libiptc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index f9b7779e..29ff356f 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -822,7 +822,7 @@ static int __iptcc_p_del_policy(struct xtc_handle *h, unsigned int num) /* save counter and counter_map information */ h->chain_iterator_cur->counter_map.maptype = - COUNTER_MAP_ZEROED; + COUNTER_MAP_NORMAL_MAP; h->chain_iterator_cur->counter_map.mappos = num-1; memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters, sizeof(h->chain_iterator_cur->counters)); -- cgit v1.2.3 From 99cd1282779beecf337c4587ffc133ecafb8130f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 10 Aug 2023 12:51:13 +0200 Subject: tests: shell: Test chain policy counter behaviour Test the last two fixes in that area. Signed-off-by: Phil Sutter --- .../tests/shell/testcases/chain/0007counters_0 | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100755 iptables/tests/shell/testcases/chain/0007counters_0 diff --git a/iptables/tests/shell/testcases/chain/0007counters_0 b/iptables/tests/shell/testcases/chain/0007counters_0 new file mode 100755 index 00000000..0b21a926 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0007counters_0 @@ -0,0 +1,78 @@ +#!/bin/bash -e + +SETUP="*filter +:FORWARD ACCEPT [13:37] +-A FORWARD -c 1 2 -j ACCEPT +-A FORWARD -c 3 4 -j ACCEPT +COMMIT" + + +### -Z with index shall zero a single chain only + +EXPECT="-P FORWARD ACCEPT -c 13 37 +-A FORWARD -c 0 0 -j ACCEPT +-A FORWARD -c 3 4 -j ACCEPT" + +$XT_MULTI iptables-restore --counters <<< "$SETUP" +$XT_MULTI iptables -Z FORWARD 1 +diff -u <(echo "$EXPECT") <($XT_MULTI iptables -vS FORWARD) + + +### -Z without index shall zero the chain and all rules + +EXPECT="-P FORWARD ACCEPT -c 0 0 +-A FORWARD -c 0 0 -j ACCEPT +-A FORWARD -c 0 0 -j ACCEPT" + +$XT_MULTI iptables -Z FORWARD +diff -u <(echo "$EXPECT") <($XT_MULTI iptables -vS FORWARD) + + +### prepare for live test + +# iptables-nft will create output chain on demand, so make sure it exists +$XT_MULTI iptables -A OUTPUT -d 127.2.3.4 -j ACCEPT + +# test runs in its own netns, lo is there but down by default +ip link set lo up + + +### pings (and pongs) hit OUTPUT policy, its counters must increase + +get_pkt_counter() { # (CHAIN) + $XT_MULTI iptables -vS $1 | awk '/^-P '$1'/{print $5; exit}' +} + +counter_inc_test() { + pkt_pre=$(get_pkt_counter OUTPUT) + ping -q -i 0.2 -c 3 127.0.0.1 + pkt_post=$(get_pkt_counter OUTPUT) + [[ $pkt_post -gt $pkt_pre ]] +} + +counter_inc_test + +# iptables-nft-restore needed --counters to create chains with them +if [[ $XT_MULTI == *xtables-nft-multi ]]; then + $XT_MULTI iptables -F OUTPUT + $XT_MULTI iptables -X OUTPUT + $XT_MULTI iptables-restore </dev/null 2>&1) +COMMIT +EOF +nft list ruleset +pkt_post=$(get_pkt_counter OUTPUT) +[[ $pkt_post -eq $((pkt_pre + 6 )) ]] -- cgit v1.2.3 From 2d6221641d66b502b1a49d3267bd8126b0448a1d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 8 Aug 2023 16:33:44 +0200 Subject: Use SOCK_CLOEXEC/O_CLOEXEC where available No need for the explicit fcntl() call, request the behaviour when opening the descriptor. One fcntl() call setting FD_CLOEXEC remains in extensions/libxt_bpf.c, the indirect syscall seems not to support passing the flag directly. Reported-by: Gaurav Gupta Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1104 Signed-off-by: Phil Sutter --- extensions/libxt_set.h | 8 +------- libiptc/libiptc.c | 8 +------- libxtables/xtables.c | 15 ++------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index 597bf7eb..685bfab9 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -10,7 +10,7 @@ static int get_version(unsigned *version) { - int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + int res, sockfd = socket(AF_INET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW); struct ip_set_req_version req_version; socklen_t size = sizeof(req_version); @@ -18,12 +18,6 @@ get_version(unsigned *version) xtables_error(OTHER_PROBLEM, "Can't open socket to ipset.\n"); - if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { - xtables_error(OTHER_PROBLEM, - "Could not set close on exec: %s\n", - strerror(errno)); - } - req_version.op = IP_SET_OP_VERSION; res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size); if (res != 0) diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 29ff356f..e4750633 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -1318,16 +1318,10 @@ retry: return NULL; } - sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); + sockfd = socket(TC_AF, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW); if (sockfd < 0) return NULL; - if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set close on exec: %s\n", - strerror(errno)); - abort(); - } - s = sizeof(info); strcpy(info.name, tablename); diff --git a/libxtables/xtables.c b/libxtables/xtables.c index e3e444ac..ba9ceaeb 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -481,14 +481,9 @@ static char *get_modprobe(void) char *ret; int count; - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); + procfile = open(PROC_SYS_MODPROBE, O_RDONLY | O_CLOEXEC); if (procfile < 0) return NULL; - if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set close on exec: %s\n", - strerror(errno)); - exit(1); - } ret = malloc(PATH_MAX); if (ret) { @@ -1023,7 +1018,7 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt) socklen_t s = sizeof(rev); int max_rev, sockfd; - sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW); + sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW); if (sockfd < 0) { if (errno == EPERM) { /* revision 0 is always supported. */ @@ -1039,12 +1034,6 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt) exit(1); } - if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set close on exec: %s\n", - strerror(errno)); - exit(1); - } - xtables_load_ko(xtables_modprobe_program, true); strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1); -- cgit v1.2.3 From 402b9b3c07c8192be3bfc0191fbf56401e26a003 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 May 2023 16:01:29 +0200 Subject: nft: Pass nft_handle to add_{target,action}() Prepare for varying rule content based on a global flag. Signed-off-by: Phil Sutter --- iptables/nft-arp.c | 2 +- iptables/nft-bridge.c | 9 +++++---- iptables/nft-ipv4.c | 2 +- iptables/nft-ipv6.c | 2 +- iptables/nft.c | 9 +++++---- iptables/nft.h | 6 ++++-- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 9868966a..14b352ce 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -151,7 +151,7 @@ static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx, else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) ret = add_verdict(r, NFT_RETURN); else - ret = add_target(r, cs->target->t); + ret = add_target(h, r, cs->target->t); } else if (strlen(cs->jumpto) > 0) { /* No goto in arptables */ ret = add_jumpto(r, cs->jumpto, NFT_JUMP); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 391a8ab7..616ae5a3 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -117,7 +117,8 @@ static int add_meta_broute(struct nftnl_rule *r) return 0; } -static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) +static int _add_action(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs) { const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); @@ -133,7 +134,7 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) } } - return add_action(r, cs, false); + return add_action(h, r, cs, false); } static int @@ -221,7 +222,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m)) break; } else { - if (add_target(r, iter->u.watcher->t)) + if (add_target(h, r, iter->u.watcher->t)) break; } } @@ -229,7 +230,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return _add_action(r, cs); + return _add_action(h, r, cs); } static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 2f10220e..663052fc 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -95,7 +95,7 @@ static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO)); + return add_action(h, r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO)); } static bool nft_ipv4_is_same(const struct iptables_command_state *a, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index d53f87c1..8bc633df 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -81,7 +81,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO)); + return add_action(h, r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO)); } static bool nft_ipv6_is_same(const struct iptables_command_state *a, diff --git a/iptables/nft.c b/iptables/nft.c index 97fd4f49..1fc12b0c 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1538,7 +1538,8 @@ static int add_meta_nftrace(struct nftnl_rule *r) return 0; } -int add_target(struct nftnl_rule *r, struct xt_entry_target *t) +int add_target(struct nft_handle *h, struct nftnl_rule *r, + struct xt_entry_target *t) { struct nftnl_expr *expr; int ret; @@ -1587,8 +1588,8 @@ int add_verdict(struct nftnl_rule *r, int verdict) return 0; } -int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, - bool goto_set) +int add_action(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs, bool goto_set) { int ret = 0; @@ -1604,7 +1605,7 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, else if (strcmp(cs->jumpto, "NFLOG") == 0) ret = add_log(r, cs); else - ret = add_target(r, cs->target->t); + ret = add_target(h, r, cs->target->t); } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a go / jump to chain */ if (goto_set) diff --git a/iptables/nft.h b/iptables/nft.h index 5acbbf82..a89aff0a 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -192,9 +192,11 @@ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes); int add_verdict(struct nftnl_rule *r, int verdict); int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct xt_entry_match *m); -int add_target(struct nftnl_rule *r, struct xt_entry_target *t); +int add_target(struct nft_handle *h, 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_action(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs, bool goto_set); int add_log(struct nftnl_rule *r, struct iptables_command_state *cs); char *get_comment(const void *data, uint32_t data_len); -- cgit v1.2.3 From ca709b5784c982de12d6eab361cfc9c900aec4c7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 May 2023 17:39:08 +0200 Subject: nft: Introduce and use bool nft_handle::compat If set, create rules using compat expressions where possible and disable the bitwise expression avoidance introduced in 323259001d617 ("nft: Optimize class-based IP prefix matches"). Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 2 +- iptables/nft.c | 10 ++++++---- iptables/nft.h | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 34ca9d16..5e0ca00e 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -198,7 +198,7 @@ void add_addr(struct nft_handle *h, struct nftnl_rule *r, for (i = 0; i < len; i++) { if (m[i] != 0xff) { - bitwise = m[i] != 0; + bitwise = h->compat || m[i] != 0; break; } } diff --git a/iptables/nft.c b/iptables/nft.c index 1fc12b0c..09ff9cf1 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1476,10 +1476,12 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, case NFT_COMPAT_RULE_APPEND: case NFT_COMPAT_RULE_INSERT: case NFT_COMPAT_RULE_REPLACE: - if (!strcmp(m->u.user.name, "limit")) - return add_nft_limit(r, m); - else if (!strcmp(m->u.user.name, "among")) + if (!strcmp(m->u.user.name, "among")) return add_nft_among(h, r, m); + else if (h->compat) + break; + else if (!strcmp(m->u.user.name, "limit")) + return add_nft_limit(r, m); else if (!strcmp(m->u.user.name, "udp")) return add_nft_udp(h, r, m); else if (!strcmp(m->u.user.name, "tcp")) @@ -1544,7 +1546,7 @@ int add_target(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_expr *expr; int ret; - if (strcmp(t->u.user.name, "TRACE") == 0) + if (!h->compat && strcmp(t->u.user.name, "TRACE") == 0) return add_meta_nftrace(r); expr = nftnl_expr_alloc("target"); diff --git a/iptables/nft.h b/iptables/nft.h index a89aff0a..fb9fc81e 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -111,6 +111,7 @@ struct nft_handle { struct list_head cmd_list; bool cache_init; int verbose; + bool compat; /* meta data, for error reporting */ struct { -- cgit v1.2.3 From 11c464ed015b52a28d90c63c69e10e5f7d4053d4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 May 2023 20:04:41 +0200 Subject: Add --compat option to *tables-nft and *-nft-restore commands The flag sets nft_handle::compat boolean, indicating a compatible rule implementation is wanted. Users expecting their created rules to be fetched from kernel by an older version of *tables-nft may use this to avoid potential compatibility issues. Changes since v1: - Expect short option '-C' in {ip,ip6,eb}tables-nft-restore command line parser - Support -C/--compat in arptables-nft-restore, too - Update man pages with the new flag Signed-off-by: Phil Sutter --- iptables/arptables-nft-restore.8 | 15 +++++++++----- iptables/arptables-nft.8 | 8 ++++++++ iptables/ebtables-nft.8 | 6 ++++++ iptables/iptables-restore.8.in | 11 ++++++++-- iptables/iptables.8.in | 7 +++++++ iptables/xshared.c | 7 ++++++- iptables/xshared.h | 1 + iptables/xtables-arp.c | 1 + iptables/xtables-eb.c | 7 ++++++- iptables/xtables-restore.c | 43 ++++++++++++++++++++++++++++++++++++---- iptables/xtables.c | 2 ++ 11 files changed, 95 insertions(+), 13 deletions(-) diff --git a/iptables/arptables-nft-restore.8 b/iptables/arptables-nft-restore.8 index 09d9082c..12ac9ebd 100644 --- a/iptables/arptables-nft-restore.8 +++ b/iptables/arptables-nft-restore.8 @@ -22,18 +22,23 @@ .SH NAME arptables-restore \- Restore ARP Tables (nft-based) .SH SYNOPSIS -\fBarptables\-restore +.BR arptables\-restore " [" --compat ] .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 +Use I/O redirection provided by your shell to read from a file. +.P .B arptables-restore flushes (deletes) all previous contents of the respective ARP Table. +.TP +.BR -C , " --compat" +Create rules in a mostly compatible way, enabling older versions of +\fBarptables\-nft\fP to correctly parse the rules received from kernel. This +mode is only useful in very specific situations and will likely impact packet +filtering performance. + .SH AUTHOR Jesper Dangaard Brouer .SH SEE ALSO \fBarptables\-save\fP(8), \fBarptables\fP(8) -.PP diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8 index ea31e084..673a7bd5 100644 --- a/iptables/arptables-nft.8 +++ b/iptables/arptables-nft.8 @@ -220,6 +220,14 @@ counters of a rule (during .B APPEND, .B REPLACE operations). +.SS "OTHER OPTIONS" +The following additional options can be specified: +.TP +\fB\-\-compat\fP +Create rules in a mostly compatible way, enabling older versions of +\fBarptables\-nft\fP to correctly parse the rules received from kernel. This +mode is only useful in very specific situations and will likely impact packet +filtering performance. .SS RULE-SPECIFICATIONS The following command line arguments make up a rule specification (as used diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index 0304b508..baada6c6 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -359,6 +359,12 @@ to try to automatically load missing kernel modules. .TP .B --concurrent Use a file lock to support concurrent scripts updating the ebtables kernel tables. +.TP +.B --compat +Create rules in a mostly compatible way, enabling older versions of +\fBebtables\-nft\fP to correctly parse the rules received from kernel. This +mode is only useful in very specific situations and will likely impact packet +filtering performance. .SS RULE SPECIFICATIONS diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index aa816f79..38309992 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -23,11 +23,11 @@ iptables-restore \(em Restore IP Tables .P ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS -\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] +\fBiptables\-restore\fP [\fB\-cChntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fIfile\fP] .P -\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] +\fBip6tables\-restore\fP [\fB\-cChntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fIfile\fP] .SH DESCRIPTION @@ -74,6 +74,13 @@ determine the executable's path. .TP \fB\-T\fP, \fB\-\-table\fP \fIname\fP Restore only the named table even if the input stream contains other ones. +.TP +\fB\-C\fP, \fB\-\-compat\fP +This flag is only relevant with \fBnft\fP-variants and ignored otherwise. If +set, rules will be created in a mostly compatible way, enabling older versions +of \fBiptables\-nft\fP to correctly parse the rules received from kernel. This +mode is only useful in very specific situations and will likely impact packet +filtering performance. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHORS diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index ecaa5553..c0e92f27 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -397,6 +397,13 @@ corresponding to that rule's position in the chain. \fB\-\-modprobe=\fP\fIcommand\fP When adding or inserting rules into a chain, use \fIcommand\fP to load any necessary modules (targets, match extensions, etc). +.TP +\fB\-\-compat\fP +This flag is only relevant with \fBnft\fP-variants and ignored otherwise. If +set, rules will be created in a mostly compatible way, enabling older versions +of \fBiptables\-nft\fP to correctly parse the rules received from kernel. This +mode is only useful in very specific situations and will likely impact packet +filtering performance. .SH LOCK FILE iptables uses the \fI@XT_LOCK_NAME@\fP file to take an exclusive lock at diff --git a/iptables/xshared.c b/iptables/xshared.c index 5f75a0a5..74b7a041 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1263,7 +1263,8 @@ xtables_printhelp(const struct xtables_rule_match *matches) printf( " --modprobe= try to insert modules using this command\n" " --set-counters -c PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); +"[!] --version -V print package version\n" +" --compat create rules compatible for parsing with old binaries\n"); if (afinfo->family == NFPROTO_ARP) { int i; @@ -1787,6 +1788,10 @@ void do_parse(int argc, char *argv[], exit_tryhelp(2, p->line); + case 15: /* --compat */ + p->compat = true; + break; + case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { if (invert) diff --git a/iptables/xshared.h b/iptables/xshared.h index a200e0d6..f69a7b43 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -283,6 +283,7 @@ struct xt_cmd_parse { int line; int verbose; bool xlate; + bool compat; struct xt_cmd_parse_ops *ops; }; diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 71518a9c..c6a9c6d6 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -78,6 +78,7 @@ static struct option original_opts[] = { { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, + { "compat", 0, 0, 15 }, { 0 } }; diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 08eec79d..ffd51efa 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -223,6 +223,7 @@ struct option ebt_original_options[] = { "init-table" , no_argument , 0, 11 }, { "concurrent" , no_argument , 0, 13 }, { "check" , required_argument, 0, 14 }, + { "compat" , no_argument , 0, 15 }, { 0 } }; @@ -335,7 +336,8 @@ static void print_help(const struct xtables_target *t, "--modprobe -M program : try to insert modules using this program\n" "--concurrent : use a file lock to support concurrent scripts\n" "--verbose -v : verbose mode\n" -"--version -V : print package version\n\n" +"--version -V : print package version\n" +"--compat : create rules compatible for parsing with old binaries\n\n" "Environment variable:\n" /*ATOMIC_ENV_VARIABLE " : if set (see above) will equal its value"*/ "\n\n"); @@ -1097,6 +1099,9 @@ print_zero: return 1; case 13 : break; + case 15: + h->compat = true; + break; case 1 : if (!strcmp(optarg, "!")) ebt_check_inverse2(optarg, argc, argv); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 23cd3498..bd8c6bc1 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -26,6 +26,7 @@ static int counters, verbose; /* Keeping track of external matches and targets. */ static const struct option options[] = { {.name = "counters", .has_arg = false, .val = 'c'}, + {.name = "compat", .has_arg = false, .val = 'C'}, {.name = "verbose", .has_arg = false, .val = 'v'}, {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "test", .has_arg = false, .val = 't'}, @@ -45,8 +46,9 @@ static const struct option options[] = { static void print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n" + fprintf(stderr, "Usage: %s [-c] [-C] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n" " [ --counters ]\n" + " [ --compat ]\n" " [ --verbose ]\n" " [ --version]\n" " [ --test ]\n" @@ -289,6 +291,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) .cb = &restore_cb, }; bool noflush = false; + bool compat = false; struct nft_handle h; int c; @@ -303,7 +306,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) exit(1); } - while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcCvVthnM:T:wW", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -311,6 +314,9 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) case 'c': counters = 1; break; + case 'C': + compat = true; + break; case 'v': verbose++; break; @@ -387,6 +393,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) } h.noflush = noflush; h.restore = true; + h.compat = compat; xtables_restore_parse(&h, &p); @@ -417,6 +424,7 @@ static const struct nft_xt_restore_cb ebt_restore_cb = { }; static const struct option ebt_restore_options[] = { + {.name = "compat", .has_arg = 0, .val = 'C'}, {.name = "noflush", .has_arg = 0, .val = 'n'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, { 0 } @@ -429,12 +437,16 @@ int xtables_eb_restore_main(int argc, char *argv[]) .cb = &ebt_restore_cb, }; bool noflush = false; + bool compat = false; struct nft_handle h; int c; - while ((c = getopt_long(argc, argv, "nv", + while ((c = getopt_long(argc, argv, "Cnv", ebt_restore_options, NULL)) != -1) { switch(c) { + case 'C': + compat = true; + break; case 'n': noflush = 1; break; @@ -443,7 +455,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) break; default: fprintf(stderr, - "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n"); + "Usage: ebtables-restore [ --compat ] [ --verbose ] [ --noflush ]\n"); exit(1); break; } @@ -451,6 +463,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) nft_init_eb(&h, "ebtables-restore"); h.noflush = noflush; + h.compat = compat; xtables_restore_parse(&h, &p); nft_fini_eb(&h); @@ -465,15 +478,37 @@ static const struct nft_xt_restore_cb arp_restore_cb = { .chain_restore = nft_cmd_chain_restore, }; +static const struct option arp_restore_options[] = { + {.name = "compat", .has_arg = 0, .val = 'C'}, + { 0 } +}; + int xtables_arp_restore_main(int argc, char *argv[]) { struct nft_xt_restore_parse p = { .in = stdin, .cb = &arp_restore_cb, }; + bool compat = false; struct nft_handle h; + int c; + + while ((c = getopt_long(argc, argv, "C", + arp_restore_options, NULL)) != -1) { + switch(c) { + case 'C': + compat = true; + break; + default: + fprintf(stderr, + "Usage: arptables-restore [ --compat ]\n"); + exit(1); + break; + } + } nft_init_arp(&h, "arptables-restore"); + h.compat = compat; xtables_restore_parse(&h, &p); nft_fini(&h); xtables_fini(); diff --git a/iptables/xtables.c b/iptables/xtables.c index 22d6ea58..25b4dbc6 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -82,6 +82,7 @@ static struct option original_opts[] = { {.name = "goto", .has_arg = 1, .val = 'g'}, {.name = "ipv4", .has_arg = 0, .val = '4'}, {.name = "ipv6", .has_arg = 0, .val = '6'}, + {.name = "compat", .has_arg = 0, .val = 15 }, {NULL}, }; @@ -161,6 +162,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, do_parse(argc, argv, &p, &cs, &args); h->verbose = p.verbose; + h->compat = p.compat; if (!nft_table_builtin_find(h, p.table)) xtables_error(VERSION_PROBLEM, -- cgit v1.2.3 From b14c971db6db069fbfd2a892c617de8d8bf26733 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 5 May 2023 20:18:38 +0200 Subject: tests: Test compat mode Extend iptables-test.py by a third mode, which is using xtables-nft-multi and passing --compat to all calls creating rules. Also add a shell testcase asserting the effectiveness of --compat by comparing debug (-vv) output. Signed-off-by: Phil Sutter --- iptables-test.py | 19 +++++-- .../shell/testcases/nft-only/0011-compat-mode_0 | 63 ++++++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) create mode 100755 iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 diff --git a/iptables-test.py b/iptables-test.py index 6f63cdbe..22b445df 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -28,6 +28,8 @@ EBTABLES_SAVE = "ebtables-save" #IPTABLES_SAVE = ['xtables-save','-4'] #IP6TABLES_SAVE = ['xtables-save','-6'] +COMPAT_ARG = "" + EXTENSIONS_PATH = "extensions" LOGFILE="/tmp/iptables-test.log" log_file = None @@ -83,7 +85,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): ''' ret = 0 - cmd = iptables + " -A " + rule + cmd = iptables + COMPAT_ARG + " -A " + rule ret = execute_cmd(cmd, filename, lineno, netns) # @@ -318,7 +320,7 @@ def run_test_file_fast(iptables, filename, netns): # load all rules via iptables_restore - command = EXECUTABLE + " " + iptables + "-restore" + command = EXECUTABLE + " " + iptables + "-restore" + COMPAT_ARG if netns: command = "ip netns exec " + netns + " " + command @@ -558,6 +560,8 @@ def main(): help='Check for missing tests') parser.add_argument('-n', '--nftables', action='store_true', help='Test iptables-over-nftables') + parser.add_argument('-c', '--nft-compat', action='store_true', + help='Test iptables-over-nftables in compat mode') parser.add_argument('-N', '--netns', action='store_const', const='____iptables-container-test', help='Test netnamespace path') @@ -577,8 +581,10 @@ def main(): variants.append("legacy") if args.nftables: variants.append("nft") + if args.nft_compat: + variants.append("nft_compat") if len(variants) == 0: - variants = [ "legacy", "nft" ] + variants = [ "legacy", "nft", "nft_compat" ] if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) @@ -598,7 +604,12 @@ def main(): total_tests = 0 for variant in variants: global EXECUTABLE - EXECUTABLE = "xtables-" + variant + "-multi" + global COMPAT_ARG + if variant == "nft_compat": + EXECUTABLE = "xtables-nft-multi" + COMPAT_ARG = " --compat" + else: + EXECUTABLE = "xtables-" + variant + "-multi" test_files = 0 tests = 0 diff --git a/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 b/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 new file mode 100755 index 00000000..c8cee8ae --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 @@ -0,0 +1,63 @@ +#!/bin/bash + +[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } + +set -e + +# reduce noise in debug output +$XT_MULTI iptables -t raw -A OUTPUT +$XT_MULTI iptables -t raw -F + +# add all the things which were "optimized" here +RULE='-t raw -A OUTPUT' + +# prefix matches on class (actually: byte) boundaries no longer need a bitwise +RULE+=' -s 10.0.0.0/8 -d 192.168.0.0/16' + +# these were turned into native matches meanwhile +# (plus -m tcp, but it conflicts with -m udp) +RULE+=' -m limit --limit 1/min' +RULE+=' -p udp -m udp --sport 1024:65535' +RULE+=' -m mark --mark 0xfeedcafe/0xfeedcafe' +RULE+=' -j TRACE' + +EXPECT_COMMON='TRACE udp opt -- in * out * 10.0.0.0/8 -> 192.168.0.0/16 limit: avg 1/min burst 5 udp spts:1024:65535 mark match 0xfeedcafe/0xfeedcafe +ip raw OUTPUT' + +EXPECT="$EXPECT_COMMON + [ payload load 1b @ network header + 12 => reg 1 ] + [ cmp eq reg 1 0x0000000a ] + [ payload load 2b @ network header + 16 => reg 1 ] + [ cmp eq reg 1 0x0000a8c0 ] + [ payload load 1b @ network header + 9 => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ limit rate 1/minute burst 5 type packets flags 0x0 ] + [ payload load 2b @ transport header + 0 => reg 1 ] + [ range eq reg 1 0x00000004 0x0000ffff ] + [ meta load mark => reg 1 ] + [ bitwise reg 1 = ( reg 1 & 0xfeedcafe ) ^ 0x00000000 ] + [ cmp eq reg 1 0xfeedcafe ] + [ counter pkts 0 bytes 0 ] + [ immediate reg 9 0x00000001 ] + [ meta set nftrace with reg 9 ] +" + +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -vv $RULE) + +EXPECT="$EXPECT_COMMON + [ payload load 4b @ network header + 12 => reg 1 ] + [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000000 ] + [ cmp eq reg 1 0x0000000a ] + [ payload load 4b @ network header + 16 => reg 1 ] + [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ] + [ cmp eq reg 1 0x0000a8c0 ] + [ payload load 1b @ network header + 9 => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ match name limit rev 0 ] + [ match name udp rev 0 ] + [ match name mark rev 1 ] + [ counter pkts 0 bytes 0 ] + [ target name TRACE rev 0 ] +" + +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables --compat -vv $RULE) -- cgit v1.2.3 From 63e4a64e943be64a7e0486838071b981074e696d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 29 Aug 2023 14:59:32 +0200 Subject: doc: fix example of xt_cpu REDIRECT uses --to-ports instead of --to-port. Fixes: 2d59208943a3 ("extension: add xt_cpu match") Signed-off-by: Victor Julien Signed-off-by: Florian Westphal --- extensions/libxt_cpu.man | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_cpu.man b/extensions/libxt_cpu.man index d9ea5c2f..c89ef08a 100644 --- a/extensions/libxt_cpu.man +++ b/extensions/libxt_cpu.man @@ -7,9 +7,9 @@ multiqueue NICs to spread network traffic on different queues. Example: .PP iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 0 -\-j REDIRECT \-\-to\-port 8080 +\-j REDIRECT \-\-to\-ports 8080 .PP iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 1 -\-j REDIRECT \-\-to\-port 8081 +\-j REDIRECT \-\-to\-ports 8081 .PP Available since Linux 2.6.36. -- cgit v1.2.3 From 35ff97e9aca8cd301ff9b9a95b0a72de1aeb700b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Aug 2023 13:47:28 +0200 Subject: Revert --compat option related commits This reverts the following commits: b14c971db6db0 ("tests: Test compat mode") 11c464ed015b5 ("Add --compat option to *tables-nft and *-nft-restore commands") ca709b5784c98 ("nft: Introduce and use bool nft_handle::compat") 402b9b3c07c81 ("nft: Pass nft_handle to add_{target,action}()") This implementation of a compatibility mode implements rules using xtables extensions if possible and thus relies upon existence of those in kernel space. Assuming no viable replacement for the internal mechanics of this mode will be found in foreseeable future, it will effectively block attempts at deprecating and removing of these xtables extensions in favor of nftables expressions and thus hinder upstream's future plans for iptables. Signed-off-by: Phil Sutter --- iptables-test.py | 19 ++----- iptables/arptables-nft-restore.8 | 15 ++---- iptables/arptables-nft.8 | 8 --- iptables/ebtables-nft.8 | 6 --- iptables/iptables-restore.8.in | 11 +--- iptables/iptables.8.in | 7 --- iptables/nft-arp.c | 2 +- iptables/nft-bridge.c | 9 ++-- iptables/nft-ipv4.c | 2 +- iptables/nft-ipv6.c | 2 +- iptables/nft-shared.c | 2 +- iptables/nft.c | 19 +++---- iptables/nft.h | 7 +-- .../shell/testcases/nft-only/0011-compat-mode_0 | 63 ---------------------- iptables/xshared.c | 7 +-- iptables/xshared.h | 1 - iptables/xtables-arp.c | 1 - iptables/xtables-eb.c | 7 +-- iptables/xtables-restore.c | 43 ++------------- iptables/xtables.c | 2 - 20 files changed, 35 insertions(+), 198 deletions(-) delete mode 100755 iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 diff --git a/iptables-test.py b/iptables-test.py index 22b445df..6f63cdbe 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -28,8 +28,6 @@ EBTABLES_SAVE = "ebtables-save" #IPTABLES_SAVE = ['xtables-save','-4'] #IP6TABLES_SAVE = ['xtables-save','-6'] -COMPAT_ARG = "" - EXTENSIONS_PATH = "extensions" LOGFILE="/tmp/iptables-test.log" log_file = None @@ -85,7 +83,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): ''' ret = 0 - cmd = iptables + COMPAT_ARG + " -A " + rule + cmd = iptables + " -A " + rule ret = execute_cmd(cmd, filename, lineno, netns) # @@ -320,7 +318,7 @@ def run_test_file_fast(iptables, filename, netns): # load all rules via iptables_restore - command = EXECUTABLE + " " + iptables + "-restore" + COMPAT_ARG + command = EXECUTABLE + " " + iptables + "-restore" if netns: command = "ip netns exec " + netns + " " + command @@ -560,8 +558,6 @@ def main(): help='Check for missing tests') parser.add_argument('-n', '--nftables', action='store_true', help='Test iptables-over-nftables') - parser.add_argument('-c', '--nft-compat', action='store_true', - help='Test iptables-over-nftables in compat mode') parser.add_argument('-N', '--netns', action='store_const', const='____iptables-container-test', help='Test netnamespace path') @@ -581,10 +577,8 @@ def main(): variants.append("legacy") if args.nftables: variants.append("nft") - if args.nft_compat: - variants.append("nft_compat") if len(variants) == 0: - variants = [ "legacy", "nft", "nft_compat" ] + variants = [ "legacy", "nft" ] if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) @@ -604,12 +598,7 @@ def main(): total_tests = 0 for variant in variants: global EXECUTABLE - global COMPAT_ARG - if variant == "nft_compat": - EXECUTABLE = "xtables-nft-multi" - COMPAT_ARG = " --compat" - else: - EXECUTABLE = "xtables-" + variant + "-multi" + EXECUTABLE = "xtables-" + variant + "-multi" test_files = 0 tests = 0 diff --git a/iptables/arptables-nft-restore.8 b/iptables/arptables-nft-restore.8 index 12ac9ebd..09d9082c 100644 --- a/iptables/arptables-nft-restore.8 +++ b/iptables/arptables-nft-restore.8 @@ -22,23 +22,18 @@ .SH NAME arptables-restore \- Restore ARP Tables (nft-based) .SH SYNOPSIS -.BR arptables\-restore " [" --compat ] +\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. -.P +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. -.TP -.BR -C , " --compat" -Create rules in a mostly compatible way, enabling older versions of -\fBarptables\-nft\fP to correctly parse the rules received from kernel. This -mode is only useful in very specific situations and will likely impact packet -filtering performance. - .SH AUTHOR Jesper Dangaard Brouer .SH SEE ALSO \fBarptables\-save\fP(8), \fBarptables\fP(8) +.PP diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8 index 673a7bd5..ea31e084 100644 --- a/iptables/arptables-nft.8 +++ b/iptables/arptables-nft.8 @@ -220,14 +220,6 @@ counters of a rule (during .B APPEND, .B REPLACE operations). -.SS "OTHER OPTIONS" -The following additional options can be specified: -.TP -\fB\-\-compat\fP -Create rules in a mostly compatible way, enabling older versions of -\fBarptables\-nft\fP to correctly parse the rules received from kernel. This -mode is only useful in very specific situations and will likely impact packet -filtering performance. .SS RULE-SPECIFICATIONS The following command line arguments make up a rule specification (as used diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index baada6c6..0304b508 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -359,12 +359,6 @@ to try to automatically load missing kernel modules. .TP .B --concurrent Use a file lock to support concurrent scripts updating the ebtables kernel tables. -.TP -.B --compat -Create rules in a mostly compatible way, enabling older versions of -\fBebtables\-nft\fP to correctly parse the rules received from kernel. This -mode is only useful in very specific situations and will likely impact packet -filtering performance. .SS RULE SPECIFICATIONS diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index 38309992..aa816f79 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -23,11 +23,11 @@ iptables-restore \(em Restore IP Tables .P ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS -\fBiptables\-restore\fP [\fB\-cChntvV\fP] [\fB\-w\fP \fIseconds\fP] +\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fIfile\fP] .P -\fBip6tables\-restore\fP [\fB\-cChntvV\fP] [\fB\-w\fP \fIseconds\fP] +\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] [\fIfile\fP] .SH DESCRIPTION @@ -74,13 +74,6 @@ determine the executable's path. .TP \fB\-T\fP, \fB\-\-table\fP \fIname\fP Restore only the named table even if the input stream contains other ones. -.TP -\fB\-C\fP, \fB\-\-compat\fP -This flag is only relevant with \fBnft\fP-variants and ignored otherwise. If -set, rules will be created in a mostly compatible way, enabling older versions -of \fBiptables\-nft\fP to correctly parse the rules received from kernel. This -mode is only useful in very specific situations and will likely impact packet -filtering performance. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHORS diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index c0e92f27..ecaa5553 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -397,13 +397,6 @@ corresponding to that rule's position in the chain. \fB\-\-modprobe=\fP\fIcommand\fP When adding or inserting rules into a chain, use \fIcommand\fP to load any necessary modules (targets, match extensions, etc). -.TP -\fB\-\-compat\fP -This flag is only relevant with \fBnft\fP-variants and ignored otherwise. If -set, rules will be created in a mostly compatible way, enabling older versions -of \fBiptables\-nft\fP to correctly parse the rules received from kernel. This -mode is only useful in very specific situations and will likely impact packet -filtering performance. .SH LOCK FILE iptables uses the \fI@XT_LOCK_NAME@\fP file to take an exclusive lock at diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 14b352ce..9868966a 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -151,7 +151,7 @@ static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx, else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) ret = add_verdict(r, NFT_RETURN); else - ret = add_target(h, r, cs->target->t); + ret = add_target(r, cs->target->t); } else if (strlen(cs->jumpto) > 0) { /* No goto in arptables */ ret = add_jumpto(r, cs->jumpto, NFT_JUMP); diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 616ae5a3..391a8ab7 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -117,8 +117,7 @@ static int add_meta_broute(struct nftnl_rule *r) return 0; } -static int _add_action(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs) +static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) { const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); @@ -134,7 +133,7 @@ static int _add_action(struct nft_handle *h, struct nftnl_rule *r, } } - return add_action(h, r, cs, false); + return add_action(r, cs, false); } static int @@ -222,7 +221,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m)) break; } else { - if (add_target(h, r, iter->u.watcher->t)) + if (add_target(r, iter->u.watcher->t)) break; } } @@ -230,7 +229,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return _add_action(h, r, cs); + return _add_action(r, cs); } static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 663052fc..2f10220e 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -95,7 +95,7 @@ static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return add_action(h, r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO)); + return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO)); } static bool nft_ipv4_is_same(const struct iptables_command_state *a, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 8bc633df..d53f87c1 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -81,7 +81,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) return -1; - return add_action(h, r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO)); + return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO)); } static bool nft_ipv6_is_same(const struct iptables_command_state *a, diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 5e0ca00e..34ca9d16 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -198,7 +198,7 @@ void add_addr(struct nft_handle *h, struct nftnl_rule *r, for (i = 0; i < len; i++) { if (m[i] != 0xff) { - bitwise = h->compat || m[i] != 0; + bitwise = m[i] != 0; break; } } diff --git a/iptables/nft.c b/iptables/nft.c index 09ff9cf1..97fd4f49 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1476,12 +1476,10 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, case NFT_COMPAT_RULE_APPEND: case NFT_COMPAT_RULE_INSERT: case NFT_COMPAT_RULE_REPLACE: - if (!strcmp(m->u.user.name, "among")) - return add_nft_among(h, r, m); - else if (h->compat) - break; - else if (!strcmp(m->u.user.name, "limit")) + if (!strcmp(m->u.user.name, "limit")) return add_nft_limit(r, m); + else if (!strcmp(m->u.user.name, "among")) + return add_nft_among(h, r, m); else if (!strcmp(m->u.user.name, "udp")) return add_nft_udp(h, r, m); else if (!strcmp(m->u.user.name, "tcp")) @@ -1540,13 +1538,12 @@ static int add_meta_nftrace(struct nftnl_rule *r) return 0; } -int add_target(struct nft_handle *h, struct nftnl_rule *r, - struct xt_entry_target *t) +int add_target(struct nftnl_rule *r, struct xt_entry_target *t) { struct nftnl_expr *expr; int ret; - if (!h->compat && strcmp(t->u.user.name, "TRACE") == 0) + if (strcmp(t->u.user.name, "TRACE") == 0) return add_meta_nftrace(r); expr = nftnl_expr_alloc("target"); @@ -1590,8 +1587,8 @@ int add_verdict(struct nftnl_rule *r, int verdict) return 0; } -int add_action(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs, bool goto_set) +int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, + bool goto_set) { int ret = 0; @@ -1607,7 +1604,7 @@ int add_action(struct nft_handle *h, struct nftnl_rule *r, else if (strcmp(cs->jumpto, "NFLOG") == 0) ret = add_log(r, cs); else - ret = add_target(h, r, cs->target->t); + ret = add_target(r, cs->target->t); } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a go / jump to chain */ if (goto_set) diff --git a/iptables/nft.h b/iptables/nft.h index fb9fc81e..5acbbf82 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -111,7 +111,6 @@ struct nft_handle { struct list_head cmd_list; bool cache_init; int verbose; - bool compat; /* meta data, for error reporting */ struct { @@ -193,11 +192,9 @@ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes); int add_verdict(struct nftnl_rule *r, int verdict); int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct xt_entry_match *m); -int add_target(struct nft_handle *h, struct nftnl_rule *r, - struct xt_entry_target *t); +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 nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs, bool goto_set); +int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set); int add_log(struct nftnl_rule *r, struct iptables_command_state *cs); char *get_comment(const void *data, uint32_t data_len); diff --git a/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 b/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 deleted file mode 100755 index c8cee8ae..00000000 --- a/iptables/tests/shell/testcases/nft-only/0011-compat-mode_0 +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } - -set -e - -# reduce noise in debug output -$XT_MULTI iptables -t raw -A OUTPUT -$XT_MULTI iptables -t raw -F - -# add all the things which were "optimized" here -RULE='-t raw -A OUTPUT' - -# prefix matches on class (actually: byte) boundaries no longer need a bitwise -RULE+=' -s 10.0.0.0/8 -d 192.168.0.0/16' - -# these were turned into native matches meanwhile -# (plus -m tcp, but it conflicts with -m udp) -RULE+=' -m limit --limit 1/min' -RULE+=' -p udp -m udp --sport 1024:65535' -RULE+=' -m mark --mark 0xfeedcafe/0xfeedcafe' -RULE+=' -j TRACE' - -EXPECT_COMMON='TRACE udp opt -- in * out * 10.0.0.0/8 -> 192.168.0.0/16 limit: avg 1/min burst 5 udp spts:1024:65535 mark match 0xfeedcafe/0xfeedcafe -ip raw OUTPUT' - -EXPECT="$EXPECT_COMMON - [ payload load 1b @ network header + 12 => reg 1 ] - [ cmp eq reg 1 0x0000000a ] - [ payload load 2b @ network header + 16 => reg 1 ] - [ cmp eq reg 1 0x0000a8c0 ] - [ payload load 1b @ network header + 9 => reg 1 ] - [ cmp eq reg 1 0x00000011 ] - [ limit rate 1/minute burst 5 type packets flags 0x0 ] - [ payload load 2b @ transport header + 0 => reg 1 ] - [ range eq reg 1 0x00000004 0x0000ffff ] - [ meta load mark => reg 1 ] - [ bitwise reg 1 = ( reg 1 & 0xfeedcafe ) ^ 0x00000000 ] - [ cmp eq reg 1 0xfeedcafe ] - [ counter pkts 0 bytes 0 ] - [ immediate reg 9 0x00000001 ] - [ meta set nftrace with reg 9 ] -" - -diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -vv $RULE) - -EXPECT="$EXPECT_COMMON - [ payload load 4b @ network header + 12 => reg 1 ] - [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000000 ] - [ cmp eq reg 1 0x0000000a ] - [ payload load 4b @ network header + 16 => reg 1 ] - [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ] - [ cmp eq reg 1 0x0000a8c0 ] - [ payload load 1b @ network header + 9 => reg 1 ] - [ cmp eq reg 1 0x00000011 ] - [ match name limit rev 0 ] - [ match name udp rev 0 ] - [ match name mark rev 1 ] - [ counter pkts 0 bytes 0 ] - [ target name TRACE rev 0 ] -" - -diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables --compat -vv $RULE) diff --git a/iptables/xshared.c b/iptables/xshared.c index 74b7a041..5f75a0a5 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1263,8 +1263,7 @@ xtables_printhelp(const struct xtables_rule_match *matches) printf( " --modprobe= try to insert modules using this command\n" " --set-counters -c PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version\n" -" --compat create rules compatible for parsing with old binaries\n"); +"[!] --version -V print package version.\n"); if (afinfo->family == NFPROTO_ARP) { int i; @@ -1788,10 +1787,6 @@ void do_parse(int argc, char *argv[], exit_tryhelp(2, p->line); - case 15: /* --compat */ - p->compat = true; - break; - case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { if (invert) diff --git a/iptables/xshared.h b/iptables/xshared.h index f69a7b43..a200e0d6 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -283,7 +283,6 @@ struct xt_cmd_parse { int line; int verbose; bool xlate; - bool compat; struct xt_cmd_parse_ops *ops; }; diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index c6a9c6d6..71518a9c 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -78,7 +78,6 @@ static struct option original_opts[] = { { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, - { "compat", 0, 0, 15 }, { 0 } }; diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index ffd51efa..08eec79d 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -223,7 +223,6 @@ struct option ebt_original_options[] = { "init-table" , no_argument , 0, 11 }, { "concurrent" , no_argument , 0, 13 }, { "check" , required_argument, 0, 14 }, - { "compat" , no_argument , 0, 15 }, { 0 } }; @@ -336,8 +335,7 @@ static void print_help(const struct xtables_target *t, "--modprobe -M program : try to insert modules using this program\n" "--concurrent : use a file lock to support concurrent scripts\n" "--verbose -v : verbose mode\n" -"--version -V : print package version\n" -"--compat : create rules compatible for parsing with old binaries\n\n" +"--version -V : print package version\n\n" "Environment variable:\n" /*ATOMIC_ENV_VARIABLE " : if set (see above) will equal its value"*/ "\n\n"); @@ -1099,9 +1097,6 @@ print_zero: return 1; case 13 : break; - case 15: - h->compat = true; - break; case 1 : if (!strcmp(optarg, "!")) ebt_check_inverse2(optarg, argc, argv); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index bd8c6bc1..23cd3498 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -26,7 +26,6 @@ static int counters, verbose; /* Keeping track of external matches and targets. */ static const struct option options[] = { {.name = "counters", .has_arg = false, .val = 'c'}, - {.name = "compat", .has_arg = false, .val = 'C'}, {.name = "verbose", .has_arg = false, .val = 'v'}, {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "test", .has_arg = false, .val = 't'}, @@ -46,9 +45,8 @@ static const struct option options[] = { static void print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-c] [-C] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n" + fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n" " [ --counters ]\n" - " [ --compat ]\n" " [ --verbose ]\n" " [ --version]\n" " [ --test ]\n" @@ -291,7 +289,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) .cb = &restore_cb, }; bool noflush = false; - bool compat = false; struct nft_handle h; int c; @@ -306,7 +303,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) exit(1); } - while ((c = getopt_long(argc, argv, "bcCvVthnM:T:wW", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -314,9 +311,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) case 'c': counters = 1; break; - case 'C': - compat = true; - break; case 'v': verbose++; break; @@ -393,7 +387,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) } h.noflush = noflush; h.restore = true; - h.compat = compat; xtables_restore_parse(&h, &p); @@ -424,7 +417,6 @@ static const struct nft_xt_restore_cb ebt_restore_cb = { }; static const struct option ebt_restore_options[] = { - {.name = "compat", .has_arg = 0, .val = 'C'}, {.name = "noflush", .has_arg = 0, .val = 'n'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, { 0 } @@ -437,16 +429,12 @@ int xtables_eb_restore_main(int argc, char *argv[]) .cb = &ebt_restore_cb, }; bool noflush = false; - bool compat = false; struct nft_handle h; int c; - while ((c = getopt_long(argc, argv, "Cnv", + while ((c = getopt_long(argc, argv, "nv", ebt_restore_options, NULL)) != -1) { switch(c) { - case 'C': - compat = true; - break; case 'n': noflush = 1; break; @@ -455,7 +443,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) break; default: fprintf(stderr, - "Usage: ebtables-restore [ --compat ] [ --verbose ] [ --noflush ]\n"); + "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n"); exit(1); break; } @@ -463,7 +451,6 @@ int xtables_eb_restore_main(int argc, char *argv[]) nft_init_eb(&h, "ebtables-restore"); h.noflush = noflush; - h.compat = compat; xtables_restore_parse(&h, &p); nft_fini_eb(&h); @@ -478,37 +465,15 @@ static const struct nft_xt_restore_cb arp_restore_cb = { .chain_restore = nft_cmd_chain_restore, }; -static const struct option arp_restore_options[] = { - {.name = "compat", .has_arg = 0, .val = 'C'}, - { 0 } -}; - int xtables_arp_restore_main(int argc, char *argv[]) { struct nft_xt_restore_parse p = { .in = stdin, .cb = &arp_restore_cb, }; - bool compat = false; struct nft_handle h; - int c; - - while ((c = getopt_long(argc, argv, "C", - arp_restore_options, NULL)) != -1) { - switch(c) { - case 'C': - compat = true; - break; - default: - fprintf(stderr, - "Usage: arptables-restore [ --compat ]\n"); - exit(1); - break; - } - } nft_init_arp(&h, "arptables-restore"); - h.compat = compat; xtables_restore_parse(&h, &p); nft_fini(&h); xtables_fini(); diff --git a/iptables/xtables.c b/iptables/xtables.c index 25b4dbc6..22d6ea58 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -82,7 +82,6 @@ static struct option original_opts[] = { {.name = "goto", .has_arg = 1, .val = 'g'}, {.name = "ipv4", .has_arg = 0, .val = '4'}, {.name = "ipv6", .has_arg = 0, .val = '6'}, - {.name = "compat", .has_arg = 0, .val = 15 }, {NULL}, }; @@ -162,7 +161,6 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, do_parse(argc, argv, &p, &cs, &args); h->verbose = p.verbose; - h->compat = p.compat; if (!nft_table_builtin_find(h, p.table)) xtables_error(VERSION_PROBLEM, -- cgit v1.2.3 From 2e704f6ddd6d056e360f3d9c11e8b6c56a20cf23 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sat, 23 Nov 2013 08:41:58 +0000 Subject: extensions: Fix checking of conntrack --ctproto 0 There are three issues in the code: 1) the check (sinfo->invflags & XT_INV_PROTO) is using the wrong mask 2) in conntrack_mt_parse it is testing (info->invert_flags & XT_INV_PROTO) before the invert bit has been set. 3) the sense of the error message is the wrong way round 1) To get the error, ! -ctstatus XXX has to be specified, since XT_INV_PROTO == XT_CONNTRACK_STATUS e.g. | iptables -I CHAIN -m conntrack ! --ctstatus ASSURED --ctproto 0 ... 3) Unlike --proto 0 (where 0 means all protocols), in the conntrack match --ctproto 0 appears to mean protocol 0, which can never be. Therefore --ctproto 0 could never match and ! --ctproto 0 will always match. Both of these should be rejected, since the user clearly cannot be intending what was specified. The attached patch resolves the issue, and also produces an error message if --ctproto 0 is specified (as well as ! --ctproto 0 ), since --ctproto 0 will never match, and ! --ctproto 0 will always match. [Phil: - Added Fixes: tag - it's a day 1 bug - Copied patch description from Bugzilla - Reorganized changes to reduce diff - Added test cases] Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=874 Fixes: 5054e85be3068 ("general conntrack match module userspace support files") Signed-off-by: Quentin Armitage Signed-off-by: Phil Sutter --- extensions/libxt_conntrack.c | 17 ++++++++--------- extensions/libxt_conntrack.t | 2 ++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 09548c29..ffbc7467 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -346,14 +346,13 @@ static void conntrack_parse(struct xt_option_call *cb) sinfo->invflags |= XT_CONNTRACK_STATE; break; case O_CTPROTO: + if (cb->val.protocol == 0) + xtables_error(PARAMETER_PROBLEM, cb->invert ? + "condition would always match protocol" : + "rule would never match protocol"); sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = cb->val.protocol; if (cb->invert) sinfo->invflags |= XT_CONNTRACK_PROTO; - if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 - && (sinfo->invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - sinfo->flags |= XT_CONNTRACK_PROTO; break; case O_CTORIGSRC: @@ -411,11 +410,11 @@ static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev) info->invert_flags |= XT_CONNTRACK_STATE; break; case O_CTPROTO: + if (cb->val.protocol == 0) + xtables_error(PARAMETER_PROBLEM, cb->invert ? + "conntrack: condition would always match protocol" : + "conntrack: rule would never match protocol"); info->l4proto = cb->val.protocol; - if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, "conntrack: rule would " - "never match protocol"); - info->match_flags |= XT_CONNTRACK_PROTO; if (cb->invert) info->invert_flags |= XT_CONNTRACK_PROTO; diff --git a/extensions/libxt_conntrack.t b/extensions/libxt_conntrack.t index db531475..2b3c5de9 100644 --- a/extensions/libxt_conntrack.t +++ b/extensions/libxt_conntrack.t @@ -25,3 +25,5 @@ -m conntrack --ctstatus EXPECTED;=;OK -m conntrack --ctstatus SEEN_REPLY;=;OK -m conntrack;;FAIL +-m conntrack --ctproto 0;;FAIL +-m conntrack ! --ctproto 0;;FAIL -- cgit v1.2.3 From ea12b1d2b191f100a6fdb83af4681364e4dba12a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 1 Sep 2023 13:16:56 +0200 Subject: tests: shell: Fix for ineffective 0007-mid-restore-flush_0 The test did not catch non-zero exit status of the spawned coprocess. To make it happen, Drop the line killing it (it will exit anyway) and pass its PID to 'wait'. While being at it, put the sleep into the correct spot (otherwise the check for chain 'foo' existence fails as it runs too early) and make said chain existence check effective. Fixes: 4e3c11a6f5a94 ("nft: Fix for ruleset flush while restoring") Signed-off-by: Phil Sutter --- .../tests/shell/testcases/nft-only/0007-mid-restore-flush_0 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 index 43880ffb..981f007f 100755 --- a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 +++ b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 @@ -13,11 +13,11 @@ COMMIT :foo [0:0] EOF -$XT_MULTI iptables-save | grep -q ':foo' +sleep 1 +$XT_MULTI iptables-save | grep -q ':foo' || exit 1 nft flush ruleset echo "COMMIT" >&"${COPROC[1]}" -sleep 1 - -[[ -n $COPROC_PID ]] && kill $COPROC_PID -wait +# close the pipe to make iptables-restore exit if it didn't error out yet +eval "exec ${COPROC[1]}>&-" +wait $COPROC_PID -- cgit v1.2.3 From 52ed0ac516db9f3a44f61dfd8b65d20631bfa95b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 6 Sep 2023 16:32:47 +0200 Subject: nft: Fix for useless meta expressions in rule A relict of legacy iptables' mandatory matching on interfaces and IP addresses is support for the '-i +' notation, basically a "match any input interface". Trying to make things better than its predecessor, iptables-nft boldly optimizes that nop away - not entirely though, the meta expression loading the interface name was left in place. While not a problem (apart from pointless overhead) in current HEAD, v1.8.7 would trip over this as a following cmp expression (for another match) was incorrectly linked to that stale meta expression, loading strange values into the respective interface name field. While being at it, merge and generalize the functions into a common one for use with ebtables' NFT_META_BRI_(I|O)IFNAME matches, too. Fixes: 0a8635183edd0 ("xtables-compat: ignore '+' interface name") Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1702 Signed-off-by: Phil Sutter --- extensions/libebt_standard.t | 4 ++++ extensions/libip6t_standard.t | 3 +++ extensions/libxt_standard.t | 2 ++ iptables/nft-arp.c | 4 ++-- iptables/nft-bridge.c | 38 ++++-------------------------------- iptables/nft-ipv4.c | 4 ++-- iptables/nft-ipv6.c | 4 ++-- iptables/nft-shared.c | 45 +++++++++++++++---------------------------- iptables/nft-shared.h | 4 ++-- 9 files changed, 36 insertions(+), 72 deletions(-) diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t index 97cb3baa..370a12f4 100644 --- a/extensions/libebt_standard.t +++ b/extensions/libebt_standard.t @@ -14,6 +14,10 @@ -o foobar;=;FAIL --logical-in br0;=;OK --logical-out br1;=;FAIL +-i + -d 00:0f:ee:d0:ba:be;-d 00:0f:ee:d0:ba:be;OK +-i + -p ip;-p IPv4;OK +--logical-in + -d 00:0f:ee:d0:ba:be;-d 00:0f:ee:d0:ba:be;OK +--logical-in + -p ip;-p IPv4;OK :FORWARD -i foobar;=;OK -o foobar;=;OK diff --git a/extensions/libip6t_standard.t b/extensions/libip6t_standard.t index a528af10..0c559cc5 100644 --- a/extensions/libip6t_standard.t +++ b/extensions/libip6t_standard.t @@ -3,3 +3,6 @@ ! -d ::;! -d ::/128;OK ! -s ::;! -s ::/128;OK -s ::/64;=;OK +:INPUT +-i + -d c0::fe;-d c0::fe/128;OK +-i + -p tcp;-p tcp;OK diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t index 6ed978e4..7c83cfa3 100644 --- a/extensions/libxt_standard.t +++ b/extensions/libxt_standard.t @@ -24,3 +24,5 @@ :FORWARD --protocol=tcp --source=1.2.3.4 --destination=5.6.7.8/32 --in-interface=eth0 --out-interface=eth1 --jump=ACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK -ptcp -s1.2.3.4 -d5.6.7.8/32 -ieth0 -oeth1 -jACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK +-i + -d 1.2.3.4;-d 1.2.3.4/32;OK +-i + -p tcp;-p tcp;OK diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 9868966a..aed39ebd 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -49,12 +49,12 @@ static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (fw->arp.iniface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, fw->arp.iniface, op); + add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op); } if (fw->arp.outiface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, fw->arp.outiface, op); + add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op); } if (fw->arp.arhrd != 0 || diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 391a8ab7..d9a8ad2b 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -65,36 +65,6 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char xtables_print_mac_and_mask(mac, mask); } -static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r, - char *iface, uint32_t op) -{ - int iface_len; - uint8_t reg; - - iface_len = strlen(iface); - - add_meta(h, r, NFT_META_BRI_IIFNAME, ®); - if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else - add_cmp_ptr(r, op, iface, iface_len + 1, reg); -} - -static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, - char *iface, uint32_t op) -{ - int iface_len; - uint8_t reg; - - iface_len = strlen(iface); - - add_meta(h, r, NFT_META_BRI_OIFNAME, ®); - if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else - add_cmp_ptr(r, op, iface, iface_len + 1, reg); -} - static int add_meta_broute(struct nftnl_rule *r) { struct nftnl_expr *expr; @@ -180,22 +150,22 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); - add_iniface(h, r, fw->in, op); + add_iface(h, r, fw->in, NFT_META_IIFNAME, op); } if (fw->out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IOUT); - add_outiface(h, r, fw->out, op); + add_iface(h, r, fw->out, NFT_META_OIFNAME, op); } if (fw->logical_in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); - add_logical_iniface(h, r, fw->logical_in, op); + add_iface(h, r, fw->logical_in, NFT_META_BRI_IIFNAME, op); } if (fw->logical_out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); - add_logical_outiface(h, r, fw->logical_out, op); + add_iface(h, r, fw->logical_out, NFT_META_BRI_OIFNAME, op); } if ((fw->bitmask & EBT_NOPROTO) == 0) { diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 2f10220e..75912847 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -51,12 +51,12 @@ static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (cs->fw.ip.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, cs->fw.ip.iniface, op); + add_iface(h, r, cs->fw.ip.iniface, NFT_META_IIFNAME, op); } if (cs->fw.ip.outiface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, cs->fw.ip.outiface, op); + add_iface(h, r, cs->fw.ip.outiface, NFT_META_OIFNAME, op); } if (cs->fw.ip.proto != 0) { diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index d53f87c1..5aef365b 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -54,12 +54,12 @@ static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx, if (cs->fw6.ipv6.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, cs->fw6.ipv6.iniface, op); + add_iface(h, r, cs->fw6.ipv6.iniface, NFT_META_IIFNAME, op); } if (cs->fw6.ipv6.outiface[0] != '\0') { op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, cs->fw6.ipv6.outiface, op); + add_iface(h, r, cs->fw6.ipv6.outiface, NFT_META_OIFNAME, op); } if (cs->fw6.ipv6.proto != 0) { diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 34ca9d16..6775578b 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -147,44 +147,29 @@ void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg) add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_iniface(struct nft_handle *h, struct nftnl_rule *r, - char *iface, uint32_t op) +void add_iface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t key, uint32_t op) { - int iface_len; + int iface_len = strlen(iface); uint8_t reg; - iface_len = strlen(iface); - add_meta(h, r, NFT_META_IIFNAME, ®); if (iface[iface_len - 1] == '+') { - if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else if (op != NFT_CMP_EQ) - add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", - strlen("INVAL/D") + 1, reg); + if (iface_len > 1) { + iface_len -= 1; + } else if (op != NFT_CMP_EQ) { + op = NFT_CMP_EQ; + iface = "INVAL/D"; + iface_len = strlen(iface) + 1; + } else { + return; /* -o + */ + } } else { - add_cmp_ptr(r, op, iface, iface_len + 1, reg); + iface_len += 1; } -} - -void add_outiface(struct nft_handle *h, struct nftnl_rule *r, - char *iface, uint32_t op) -{ - int iface_len; - uint8_t reg; - iface_len = strlen(iface); - - add_meta(h, r, NFT_META_OIFNAME, ®); - if (iface[iface_len - 1] == '+') { - if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else if (op != NFT_CMP_EQ) - add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", - strlen("INVAL/D") + 1, reg); - } else { - add_cmp_ptr(r, op, iface, iface_len + 1, reg); - } + add_meta(h, r, key, ®); + add_cmp_ptr(r, op, iface, iface_len, reg); } void add_addr(struct nft_handle *h, struct nftnl_rule *r, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 4f47058d..51d1e460 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -95,8 +95,8 @@ void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, uint void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg); void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg); void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg); -void add_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); -void add_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op); +void add_iface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t key, uint32_t op); void add_addr(struct nft_handle *h, struct nftnl_rule *r, enum nft_payload_bases base, int offset, void *data, void *mask, size_t len, uint32_t op); void add_proto(struct nft_handle *h, struct nftnl_rule *r, int offset, size_t len, -- cgit v1.2.3 From cb884bf73a4d8585a7739702ca690fdc590341ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 6 Sep 2023 19:02:52 +0200 Subject: include: linux: Update kernel.h Its contents were moved into const.h and sysinfo.h, apply these changes to the cached copies. Fixes for the following warning when compiling xtables-monitor.c with new kernel headers in /usr/include: | In file included from ../include/linux/netfilter/x_tables.h:3, | from ../include/xtables.h:19, | from xtables-monitor.c:36: | ../include/linux/kernel.h:7: warning: "__ALIGN_KERNEL" redefined | 7 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) | | | In file included from /usr/include/linux/netlink.h:5, | from /home/n0-1/git/libmnl/install/include/libmnl/libmnl.h:9, | from xtables-monitor.c:30: | /usr/include/linux/const.h:31: note: this is the location of the previous definition | 31 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) | | Signed-off-by: Phil Sutter --- include/linux/const.h | 36 ++++++++++++++++++++++++++++++++++++ include/linux/kernel.h | 29 ++++------------------------- include/linux/sysinfo.h | 25 +++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 include/linux/const.h create mode 100644 include/linux/sysinfo.h diff --git a/include/linux/const.h b/include/linux/const.h new file mode 100644 index 00000000..1eb84b50 --- /dev/null +++ b/include/linux/const.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* const.h: Macros for dealing with constants. */ + +#ifndef _LINUX_CONST_H +#define _LINUX_CONST_H + +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specifiers unilaterally. We + * use the following macros to deal with this. + * + * Similarly, _AT() will cast an expression with a type in C, but + * leave it unchanged in asm. + */ + +#ifdef __ASSEMBLY__ +#define _AC(X,Y) X +#define _AT(T,X) X +#else +#define __AC(X,Y) (X##Y) +#define _AC(X,Y) __AC(X,Y) +#define _AT(T,X) ((T)(X)) +#endif + +#define _UL(x) (_AC(x, UL)) +#define _ULL(x) (_AC(x, ULL)) + +#define _BITUL(x) (_UL(1) << (x)) +#define _BITULL(x) (_ULL(1) << (x)) + +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +#endif /* _LINUX_CONST_H */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d4c59f65..5413a8c5 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -1,29 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _LINUX_KERNEL_H #define _LINUX_KERNEL_H -/* - * 'kernel.h' contains some often-used function prototypes etc - */ -#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) -#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#include +#include - -#define SI_LOAD_SHIFT 16 -struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ - unsigned long totalram; /* Total usable main memory size */ - unsigned long freeram; /* Available memory size */ - unsigned long sharedram; /* Amount of shared memory */ - unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalswap; /* Total swap space size */ - unsigned long freeswap; /* swap space still available */ - unsigned short procs; /* Number of current processes */ - unsigned short pad; /* explicit padding for m68k */ - unsigned long totalhigh; /* Total high memory size */ - unsigned long freehigh; /* Available high memory size */ - unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ -}; - -#endif +#endif /* _LINUX_KERNEL_H */ diff --git a/include/linux/sysinfo.h b/include/linux/sysinfo.h new file mode 100644 index 00000000..435d5c23 --- /dev/null +++ b/include/linux/sysinfo.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_SYSINFO_H +#define _LINUX_SYSINFO_H + +#include + +#define SI_LOAD_SHIFT 16 +struct sysinfo { + __kernel_long_t uptime; /* Seconds since boot */ + __kernel_ulong_t loads[3]; /* 1, 5, and 15 minute load averages */ + __kernel_ulong_t totalram; /* Total usable main memory size */ + __kernel_ulong_t freeram; /* Available memory size */ + __kernel_ulong_t sharedram; /* Amount of shared memory */ + __kernel_ulong_t bufferram; /* Memory used by buffers */ + __kernel_ulong_t totalswap; /* Total swap space size */ + __kernel_ulong_t freeswap; /* swap space still available */ + __u16 procs; /* Number of current processes */ + __u16 pad; /* Explicit padding for m68k */ + __kernel_ulong_t totalhigh; /* Total high memory size */ + __kernel_ulong_t freehigh; /* Available high memory size */ + __u32 mem_unit; /* Memory unit size in bytes */ + char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)]; /* Padding: libc5 uses this.. */ +}; + +#endif /* _LINUX_SYSINFO_H */ -- cgit v1.2.3 From 54526ee6ecb8bf775557a5afe1b42520ae5f3817 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 30 Sep 2023 01:35:48 +0200 Subject: build: Bump dependency on libnftnl Recently added support for broute table emulation requires libnftnl version 1.2.6. Fixes: 73611d5582e72 ("ebtables-nft: add broute table emulation") Signed-off-by: Phil Sutter --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 488c01eb..b6247ce7 100644 --- a/configure.ac +++ b/configure.ac @@ -134,7 +134,7 @@ if test "x$enable_nftables" = "xyes"; then exit 1 fi - PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.6], [nftables=1], [nftables=0]) + PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.2.6], [nftables=1], [nftables=0]) if test "$nftables" = 0; then -- cgit v1.2.3 From 8ae55c2a331e932c0aeef8c6c138bf60deb9fd42 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 10 Oct 2023 11:20:12 +0200 Subject: configure: Bump version for 1.8.10 release Signed-off-by: Pablo Neira Ayuso --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b6247ce7..d99fa3b9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT([iptables], [1.8.9]) +AC_INIT([iptables], [1.8.10]) # See libtool.info "Libtool's versioning system" libxtables_vcurrent=19 -- cgit v1.2.3 From e2d7ee9c49b582f399ad4ba2da2ee1b3e1f89620 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Oct 2023 17:27:42 +0200 Subject: libiptc: Fix for another segfault due to chain index NULL pointer Chain rename code missed to adjust the num_chains value which is used to calculate the number of chain index buckets to allocate during an index rebuild. So with the right number of chains present, the last chain in a middle bucket being renamed (and ending up in another bucket) triggers an index rebuild based on false data. The resulting NULL pointer index bucket then causes a segfault upon reinsertion. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1713 Fixes: 64ff47cde38e4 ("libiptc: fix chain rename bug in libiptc") --- .../shell/testcases/chain/0008rename-segfault2_0 | 32 ++++++++++++++++++++++ libiptc/libiptc.c | 4 +++ 2 files changed, 36 insertions(+) create mode 100755 iptables/tests/shell/testcases/chain/0008rename-segfault2_0 diff --git a/iptables/tests/shell/testcases/chain/0008rename-segfault2_0 b/iptables/tests/shell/testcases/chain/0008rename-segfault2_0 new file mode 100755 index 00000000..bc473d25 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0008rename-segfault2_0 @@ -0,0 +1,32 @@ +#!/bin/bash +# +# Another funny rename bug in libiptc: +# If there is a chain index bucket with only a single chain in it and it is not +# the last one and that chain is renamed, a chain index rebuild is triggered. +# Since TC_RENAME_CHAIN missed to temporarily decrement num_chains value, an +# extra index is allocated and remains NULL. The following insert of renamed +# chain then segfaults. + +( + echo "*filter" + # first bucket + for ((i = 0; i < 40; i++)); do + echo ":chain-a-$i - [0:0]" + done + # second bucket + for ((i = 0; i < 40; i++)); do + echo ":chain-b-$i - [0:0]" + done + # third bucket, just make sure it exists + echo ":chain-c-0 - [0:0]" + echo "COMMIT" +) | $XT_MULTI iptables-restore + +# rename all chains of the middle bucket +( + echo "*filter" + for ((i = 0; i < 40; i++)); do + echo "-E chain-b-$i chain-d-$i" + done + echo "COMMIT" +) | $XT_MULTI iptables-restore --noflush diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index e4750633..9712a363 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -2384,12 +2384,16 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, return 0; } + handle->num_chains--; + /* This only unlinks "c" from the list, thus no free(c) */ iptcc_chain_index_delete_chain(c, handle); /* Change the name of the chain */ strncpy(c->name, newname, sizeof(IPT_CHAINLABEL) - 1); + handle->num_chains++; + /* Insert sorted into to list again */ iptc_insert_chain(handle, c); -- cgit v1.2.3 From 920ece2b392fb83bd26416e0e6f8f6a847aacbaa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Oct 2023 17:54:53 +0200 Subject: extensions: string: Clarify description of --to String match indeed returns a match as long as the given pattern starts in the range of --from and --to, update the text accordingly. Also add a note regarding fragment boundaries. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1707 --- extensions/libxt_string.man | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man index 2a470ece..efdda492 100644 --- a/extensions/libxt_string.man +++ b/extensions/libxt_string.man @@ -7,9 +7,13 @@ Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morri Set the offset from which it starts looking for any matching. If not passed, default is 0. .TP \fB\-\-to\fP \fIoffset\fP -Set the offset up to which should be scanned. That is, byte \fIoffset\fP-1 -(counting from 0) is the last one that is scanned. +Set the offset up to which should be scanned. If the pattern does not start +within this offset, it is not considered a match. If not passed, default is the packet size. +A second function of this parameter is instructing the kernel how much data +from the packet should be provided. With non-linear skbuffs (e.g. due to +fragmentation), a pattern extending past this offset may not be found. Also see +the related note below about Boyer-Moore algorithm in these cases. .TP [\fB!\fP] \fB\-\-string\fP \fIpattern\fP Matches the given pattern. -- cgit v1.2.3 From 6b1a394b2280d233d8e96c8e92deb1c5125b1ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 Oct 2023 16:08:16 -0700 Subject: iptables: reenable 'pointer-bool-conversion' warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (this does not seem to be needed any more) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I38949223393736d97623359b253fdfa1bcf222a2 --- extensions/Android.bp | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/Android.bp b/extensions/Android.bp index 8a6b6e99..83561153 100644 --- a/extensions/Android.bp +++ b/extensions/Android.bp @@ -20,8 +20,6 @@ cc_defaults { "-Wno-format", "-Wno-missing-field-initializers", - // libxt_recent.c:202:11: error: address of array 'info->name' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] - "-Wno-pointer-bool-conversion", "-Wno-tautological-pointer-compare", ], } -- cgit v1.2.3 From f171d14045ae633eb2aa6cf52e3f330b5b5f6cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 Oct 2023 16:42:40 -0700 Subject: Revert "ANDROID: fix build for missing ETH_ALEN definition" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7608e136bd495fe734ad18a6897dd4425e1a633b. (in prep for merge of 1.8.8 which includes this) Test: N/A, does not build Signed-off-by: Maciej Żenczykowski Change-Id: I370d68c1caa8dcfb5d5934ee6e6324e8e2e519c2 --- libxtables/xtables.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 35fa6258..9d309e33 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -45,9 +45,6 @@ #include #include /* INT_MAX in ip_tables.h/ip6_tables.h */ -#ifdef __BIONIC__ -#include /* ETH_ALEN */ -#endif #include #include #include -- cgit v1.2.3 From 68c02e4c8ac48136e830c636bda64da13a36ecd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 Oct 2023 16:45:33 -0700 Subject: bump to 1.8.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ibbedf6e78258e1f0ab77f4a615004e818ffd3fe4 --- METADATA | 4 ++-- config.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/METADATA b/METADATA index d5267994..857a0617 100644 --- a/METADATA +++ b/METADATA @@ -11,7 +11,7 @@ third_party { type: GIT value: "git://git.netfilter.org/iptables" } - version: "v1.8.7" - last_upgrade_date { year: 2021 month: 3 day: 23 } + version: "v1.8.8" + last_upgrade_date { year: 2022 month: 5 day: 13 } license_type: RESTRICTED } diff --git a/config.h b/config.h index f4a827d6..1711f0d7 100644 --- a/config.h +++ b/config.h @@ -62,7 +62,7 @@ #define PACKAGE_NAME "iptables" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "iptables 1.8.7" +#define PACKAGE_STRING "iptables 1.8.8" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "iptables" @@ -71,7 +71,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.8.7" +#define PACKAGE_VERSION "1.8.8" /* The size of `struct ip6_hdr', as computed by sizeof. */ #define SIZEOF_STRUCT_IP6_HDR 40 @@ -80,7 +80,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.8.7" +#define VERSION "1.8.8" /* Location of the iptables lock file */ #define XT_LOCK_NAME "/system/etc/xtables.lock" -- cgit v1.2.3 From 6e18c5e43a73ff31d89258254984999babe11c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 Oct 2023 18:34:19 -0700 Subject: bump to 1.8.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I30fd835c7779778581e605bd0bd82bbec5de8265 --- METADATA | 4 ++-- config.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/METADATA b/METADATA index 857a0617..7423808f 100644 --- a/METADATA +++ b/METADATA @@ -11,7 +11,7 @@ third_party { type: GIT value: "git://git.netfilter.org/iptables" } - version: "v1.8.8" - last_upgrade_date { year: 2022 month: 5 day: 13 } + version: "v1.8.9" + last_upgrade_date { year: 2023 month: 1 day: 10 } license_type: RESTRICTED } diff --git a/config.h b/config.h index 1711f0d7..57aa1c5e 100644 --- a/config.h +++ b/config.h @@ -62,7 +62,7 @@ #define PACKAGE_NAME "iptables" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "iptables 1.8.8" +#define PACKAGE_STRING "iptables 1.8.9" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "iptables" @@ -71,7 +71,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.8.8" +#define PACKAGE_VERSION "1.8.9" /* The size of `struct ip6_hdr', as computed by sizeof. */ #define SIZEOF_STRUCT_IP6_HDR 40 @@ -80,7 +80,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.8.8" +#define VERSION "1.8.9" /* Location of the iptables lock file */ #define XT_LOCK_NAME "/system/etc/xtables.lock" -- cgit v1.2.3 From 0b40e0cb0eaaeb50db17a4b31dfa18b2673334bb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 22 Feb 2023 16:36:16 +0100 Subject: include: Add missing linux/netfilter/xt_LOG.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When merging IP-version-specific LOG extensions, a dependency to that header was introduced without caching it. Fix this and drop the now unused ip{,6}t_LOG.h files. Reported-by: Thomas Devoogdt Fixes: 87e4f1bf0b87b ("extensions: libip*t_LOG: Merge extensions") Signed-off-by: Phil Sutter Signed-off-by: Maciej Żenczykowski Change-Id: I58da200a4ee3ee1529c00e617d67358a4b1c39a9 (cherry picked from commit 8030e5444681e16ac2f481ddad73e33fab376147) --- include/linux/netfilter/xt_LOG.h | 20 ++++++++++++++++++++ include/linux/netfilter_ipv4/ipt_LOG.h | 19 ------------------- include/linux/netfilter_ipv6/ip6t_LOG.h | 19 ------------------- 3 files changed, 20 insertions(+), 38 deletions(-) create mode 100644 include/linux/netfilter/xt_LOG.h delete mode 100644 include/linux/netfilter_ipv4/ipt_LOG.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_LOG.h diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h new file mode 100644 index 00000000..167d4ddd --- /dev/null +++ b/include/linux/netfilter/xt_LOG.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _XT_LOG_H +#define _XT_LOG_H + +/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */ +#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define XT_LOG_TCPOPT 0x02 /* Log TCP options */ +#define XT_LOG_IPOPT 0x04 /* Log IP options */ +#define XT_LOG_UID 0x08 /* Log UID owning local socket */ +#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define XT_LOG_MASK 0x2f + +struct xt_log_info { + unsigned char level; + unsigned char logflags; + char prefix[30]; +}; + +#endif /* _XT_LOG_H */ diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h deleted file mode 100644 index dcdbadf9..00000000 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IPT_LOG_H -#define _IPT_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IPT_LOG_IPOPT 0x04 /* Log IP options */ -#define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ -#define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IPT_LOG_MASK 0x2f - -struct ipt_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h deleted file mode 100644 index 9dd5579e..00000000 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IP6T_LOG_H -#define _IP6T_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IP6T_LOG_IPOPT 0x04 /* Log IP options */ -#define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ -#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ -#define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IP6T_LOG_MASK 0x2f - -struct ip6t_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ -- cgit v1.2.3 From 97823ea15ca277ec723a02bc9d4081be5dc3037c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 Oct 2023 19:43:59 -0700 Subject: ANDROID: extensions/libxt_LOG.c: manually define prioritynames[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on looking at: https://git.netfilter.org/iptables/commit/?h=v1.8.10&id=87e4f1bf0b87b23f0fe29e5f9976d64843de8785 Test: builds, but the following fail: $ atest NetdBinderTest IptablesRestoreControllerTest NetdBinderTest#TetherGetStats NetdBinderTest#StrictSetUidCleartextPenalty NetdBinderTest#FirewallSetFirewallType NetdBinderTest#FirewallSetInterfaceRule NetdBinderTest#TetherForwardAddRemove IptablesRestoreControllerTest#TestCommandTimeout Signed-off-by: Maciej Żenczykowski Change-Id: Id55f855d05c8f0e9b7a01a881da3cc4b211341ae --- extensions/libxt_LOG.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c index b6fe0b2e..d930bb97 100644 --- a/extensions/libxt_LOG.c +++ b/extensions/libxt_LOG.c @@ -1,7 +1,34 @@ #include #include +#ifndef __BIONIC__ #define SYSLOG_NAMES #include +#else /* __BIONIC__ */ +#include +/* 'prioritynames[]' should come from syslog.h, but bionic doesn't provide it... + * It is a lookup array from a string name to a non unique LOG_* value, + * but it can also be used in reverse (in which case first match wins), + * so the order matters. + * iptables 1.8.9 only uses it for the level -> name lookup. + */ +static const struct { + const char * const c_name; + const int c_val; +} prioritynames[] = { + { .c_name = "emerg", .c_val = LOG_EMERG, }, + { .c_name = "panic", .c_val = LOG_EMERG, }, + { .c_name = "alert", .c_val = LOG_ALERT, }, + { .c_name = "crit", .c_val = LOG_CRIT, }, + { .c_name = "err", .c_val = LOG_ERR, }, + { .c_name = "error", .c_val = LOG_ERR, }, + { .c_name = "warn", .c_val = LOG_WARNING, }, + { .c_name = "warning", .c_val = LOG_WARNING, }, + { .c_name = "notice", .c_val = LOG_NOTICE, }, + { .c_name = "info", .c_val = LOG_INFO, }, + { .c_name = "debug", .c_val = LOG_DEBUG, }, + { .c_name = NULL, .c_val = -1, }, +}; +#endif /* __BIONIC__ */ #include #include -- cgit v1.2.3 From 9122b27635055a26c8a1d336bcf7382945dc576f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 22 Oct 2023 01:16:19 -0700 Subject: ANDROID: unconditionally use 'all' for proto 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0 actually meaning 'all' is special, since 0 actually means IPPROTO_HOPOPTS Tests updated via: sed -ri 's@0 --@all --@g' iptables/tests/shell/testcases/*/*{output,line}* Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I243de287dd15e9cd853cc08f840953610a8f0bf4 --- iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 | 8 ++++---- .../tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 | 2 +- iptables/tests/shell/testcases/iptables/0002-verbose-output_0 | 4 ++-- iptables/xshared.c | 4 +++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index cc18a94b..7ecfa718 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -33,11 +33,11 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::1 feed:babe::2 - 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::4 feed:babe::5 + 0 0 ACCEPT all -- eth2 eth3 feed:babe::1 feed:babe::2 + 0 0 ACCEPT all -- eth2 eth3 feed:babe::4 feed:babe::5 0 0 58 -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 - 0 0 0 -- * * ::/0 ::/0 dst length:42 rt type:23 - 0 0 LOG 0 -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 + 0 0 all -- * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 LOG all -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 index 1a3af46f..bea1a690 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 @@ -12,5 +12,5 @@ EOF EXPECT='Chain FORWARD (policy ACCEPT) target prot opt source destination -ACCEPT 0 -- 0.0.0.0/0 0.0.0.0/0 ' +ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ' diff -u <(echo "$EXPECT") <($XT_MULTI iptables -n -L FORWARD) diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index 15c72af3..5d2af4c8 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -21,8 +21,8 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.1 10.0.0.2 - 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.4 10.0.0.5 + 0 0 ACCEPT all -- eth2 eth3 10.0.0.1 10.0.0.2 + 0 0 ACCEPT all -- eth2 eth3 10.0.0.4 10.0.0.5 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/xshared.c b/iptables/xshared.c index f93529b1..60955147 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -1090,7 +1090,9 @@ void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); - if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname) + if (!proto) + printf(FMT("%-4s ", "%s "), "all"); + else if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname) printf(FMT("%-4hu ", "%hu "), proto); else printf(FMT("%-4s ", "%s "), pname); -- cgit v1.2.3 From d8513a9276f7b1e76139a8cfc25f84d6a86532ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 22 Oct 2023 10:57:43 -0700 Subject: bump to 1.8.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ic32f5441bea2680b95dacac764a56d63f0283f69 --- METADATA | 4 ++-- config.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/METADATA b/METADATA index 7423808f..82462d16 100644 --- a/METADATA +++ b/METADATA @@ -11,7 +11,7 @@ third_party { type: GIT value: "git://git.netfilter.org/iptables" } - version: "v1.8.9" - last_upgrade_date { year: 2023 month: 1 day: 10 } + version: "v1.8.10" + last_upgrade_date { year: 2023 month: 10 day: 10 } license_type: RESTRICTED } diff --git a/config.h b/config.h index 57aa1c5e..c06a23a1 100644 --- a/config.h +++ b/config.h @@ -62,7 +62,7 @@ #define PACKAGE_NAME "iptables" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "iptables 1.8.9" +#define PACKAGE_STRING "iptables 1.8.10" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "iptables" @@ -71,7 +71,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.8.9" +#define PACKAGE_VERSION "1.8.10" /* The size of `struct ip6_hdr', as computed by sizeof. */ #define SIZEOF_STRUCT_IP6_HDR 40 @@ -80,7 +80,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.8.9" +#define VERSION "1.8.10" /* Location of the iptables lock file */ #define XT_LOCK_NAME "/system/etc/xtables.lock" -- cgit v1.2.3 From 85c38ce6c626efe5cd2d6770d5c0834678f78712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 Oct 2023 02:55:59 +0000 Subject: Revert "ANDROID: extensions/libxt_LOG.c: manually define prioritynames[]" This reverts commit 97823ea15ca277ec723a02bc9d4081be5dc3037c. Reason for revert: no longer needed after bionic header update Change-Id: If9641bbc2462a43e91f26d59957d66e55dea42c9 --- extensions/libxt_LOG.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c index d930bb97..b6fe0b2e 100644 --- a/extensions/libxt_LOG.c +++ b/extensions/libxt_LOG.c @@ -1,34 +1,7 @@ #include #include -#ifndef __BIONIC__ #define SYSLOG_NAMES #include -#else /* __BIONIC__ */ -#include -/* 'prioritynames[]' should come from syslog.h, but bionic doesn't provide it... - * It is a lookup array from a string name to a non unique LOG_* value, - * but it can also be used in reverse (in which case first match wins), - * so the order matters. - * iptables 1.8.9 only uses it for the level -> name lookup. - */ -static const struct { - const char * const c_name; - const int c_val; -} prioritynames[] = { - { .c_name = "emerg", .c_val = LOG_EMERG, }, - { .c_name = "panic", .c_val = LOG_EMERG, }, - { .c_name = "alert", .c_val = LOG_ALERT, }, - { .c_name = "crit", .c_val = LOG_CRIT, }, - { .c_name = "err", .c_val = LOG_ERR, }, - { .c_name = "error", .c_val = LOG_ERR, }, - { .c_name = "warn", .c_val = LOG_WARNING, }, - { .c_name = "warning", .c_val = LOG_WARNING, }, - { .c_name = "notice", .c_val = LOG_NOTICE, }, - { .c_name = "info", .c_val = LOG_INFO, }, - { .c_name = "debug", .c_val = LOG_DEBUG, }, - { .c_name = NULL, .c_val = -1, }, -}; -#endif /* __BIONIC__ */ #include #include -- cgit v1.2.3