summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/generic.txlate6
-rw-r--r--extensions/libebt_802_3.t6
-rw-r--r--extensions/libxt_conntrack.c12
-rw-r--r--extensions/libxt_pkttype.c2
-rw-r--r--extensions/libxt_sctp.c4
-rw-r--r--extensions/libxt_sctp.man4
-rw-r--r--extensions/libxt_sctp.t4
-rw-r--r--extensions/libxt_sctp.txlate2
-rw-r--r--include/linux/netfilter/nf_tables.h483
-rw-r--r--iptables/nft-arp.c57
-rw-r--r--iptables/nft-bridge.c146
-rw-r--r--iptables/nft-cmd.c1
-rw-r--r--iptables/nft-cmd.h3
-rw-r--r--iptables/nft-ipv4.c52
-rw-r--r--iptables/nft-ipv6.c39
-rw-r--r--iptables/nft-shared.c337
-rw-r--r--iptables/nft-shared.h112
-rw-r--r--iptables/nft.c12
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_012
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0008-ebtables-among_098
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0002-verbose-output_020
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0002-verbose-output_04
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt26
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0010-native-delinearize_09
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-nft-native.txt41
-rw-r--r--iptables/xshared.c8
-rw-r--r--iptables/xshared.h5
-rw-r--r--iptables/xtables-eb.c28
-rw-r--r--iptables/xtables-restore.c7
-rw-r--r--libxtables/xtables.c14
32 files changed, 1263 insertions, 295 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/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 ?
"!= " : "");
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 */
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
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,15 +327,29 @@ 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
*
* @NFTA_SET_TABLE: table name (NLA_STRING)
@@ -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)
@@ -478,6 +537,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
*
* @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
@@ -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)
@@ -899,6 +1014,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
*
* @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
@@ -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
*
@@ -1018,6 +1196,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
*
* @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
@@ -1040,6 +1233,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
*
* @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
@@ -1084,6 +1304,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
*
* @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
@@ -1165,6 +1400,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
*
* @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
@@ -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,11 +1611,25 @@ 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
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
@@ -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)
@@ -1371,6 +1669,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
*
* @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
@@ -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-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..d1385cc3 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, &reg);
- 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))
@@ -170,6 +189,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 +197,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,16 +226,18 @@ 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)
{
struct ebt_entry *fw = &cs->eb;
unsigned char addr[ETH_ALEN];
unsigned short int ethproto;
+ uint8_t op;
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 +245,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,18 +258,22 @@ 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):
- get_cmp_data(e, &ethproto, sizeof(ethproto), &inv);
- fw->ethproto = ethproto;
+ __get_cmp_data(e, &ethproto, 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;
@@ -294,28 +318,51 @@ 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;
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;
+ }
+
+ 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 = 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(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 +372,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 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",
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 +462,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 +520,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,
@@ -587,7 +637,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("! ");
if (bitmask & EBT_802_3) {
- printf("length ");
+ printf("Length ");
return;
}
@@ -601,7 +651,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)
@@ -840,7 +890,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)) {
@@ -863,9 +916,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/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-ipv4.c b/iptables/nft-ipv4.c
index 59c4a41f..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,13 +199,15 @@ 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;
+ case offsetof(struct iphdr, ttl):
+ 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 9a29d18b..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;
@@ -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 74e19cca..996cff99 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -10,6 +10,7 @@
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
+#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -25,6 +26,9 @@
#include <linux/netfilter/xt_limit.h>
#include <linux/netfilter/xt_NFLOG.h>
#include <linux/netfilter/xt_mark.h>
+#include <linux/netfilter/xt_pkttype.h>
+
+#include <linux/netfilter_ipv6/ip6t_hl.h>
#include <libmnl/libmnl.h>
#include <libnftnl/rule.h>
@@ -296,6 +300,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;
@@ -313,12 +327,28 @@ 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;
+}
+
+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;
}
@@ -369,6 +399,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;
}
@@ -439,39 +472,61 @@ 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)
+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;
+
+ switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_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;
}
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;
@@ -487,51 +542,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);
+
+ if (!reg)
+ return;
- 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;
+ 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 *
@@ -836,6 +914,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;
@@ -856,7 +936,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 */
@@ -882,10 +972,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;
@@ -893,6 +982,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)
{
@@ -922,7 +1012,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;
@@ -935,30 +1025,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;
}
}
@@ -977,18 +1077,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;
}
@@ -1125,20 +1229,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;
}
}
@@ -1189,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);
}
@@ -1424,3 +1542,84 @@ 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;
+}
+
+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 b0404904..3d935d53 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -38,13 +38,36 @@ 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 nft_xt_ctx {
@@ -58,25 +81,50 @@ 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;
+}
+
+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 +132,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);
@@ -159,6 +211,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,
@@ -212,7 +265,14 @@ 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
+
+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 ec79f2bc..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
@@ -1167,7 +1164,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);
@@ -1208,8 +1205,9 @@ 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), &reg);
+ reg = nft_get_next_reg(reg, ETH_ALEN);
+ e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
+ sizeof(struct in_addr), reg);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
@@ -3360,6 +3358,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/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
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
diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
index 7624cbab..2a1518d6 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 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/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")
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/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
new file mode 100755
index 00000000..7859e76c
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+nft -v >/dev/null || exit 0
+
+set -e
+
+unshare -n bash -c "nft -f $(dirname $0)/0010-nft-native.txt;
+ diff -u -Z $(dirname $0)/0010-iptables-nft-save.txt <($XT_MULTI iptables-save | grep -v '^#')"
diff --git a/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt
new file mode 100644
index 00000000..d37ce873
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt
@@ -0,0 +1,41 @@
+table ip filter {
+ chain INPUT {
+ type filter hook input priority filter; policy accept;
+
+ ip saddr 1.2.3.4 tcp dport 23 accept
+ ip saddr 1.2.3.0/24 ip daddr 0.0.0.0 udp dport 67-69 drop
+
+ ip saddr 1.0.0.0/8 ip daddr 0.0.0.0 tcp sport 1024-65535 tcp dport 443 tcp flags syn / syn,ack accept
+ tcp dport 443 tcp flags syn comment "checks if SYN bit is set"
+ tcp flags syn / syn,rst,ack,fin comment "same as iptables --syn"
+ tcp flags & syn == syn
+ tcp flags & (syn | ack) != (syn | ack )
+
+ ip daddr 0.0.0.0/1 ip ttl 1 drop
+ ip daddr 0.0.0.0/2 ip ttl > 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
+ }
+}
diff --git a/iptables/xshared.c b/iptables/xshared.c
index bd4e1022..69515789 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);
@@ -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("%-5s", "%s "), pname);
+ if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname)
+ printf(FMT("%-4hu ", "%hu "), proto);
else
- printf(FMT("%-5hu", "%hu "), proto);
+ printf(FMT("%-4s ", "%s "), pname);
}
void save_rule_details(const char *iniface, unsigned const char *iniface_mask,
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 b986fd9e..631a3ceb 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -157,22 +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_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_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 */
struct option ebt_original_options[] =
@@ -897,11 +881,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",
@@ -925,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");
@@ -945,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");
@@ -982,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;
@@ -993,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");
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 1363f96a..c9d4ffbf 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",
- xt_params->program_name, line);
+ fprintf(stderr, "%s: line %u failed",
+ xt_params->program_name, h->error.lineno);
+ if (errno)
+ fprintf(stderr, ": %s.", nft_strerror(errno));
+ fprintf(stderr, "\n");
exit(1);
}
}
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;