summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-07-28 14:17:35 +0200
committerPatrick McHardy <kaber@trash.net>2009-07-28 14:17:35 +0200
commitebfd6822498965cdb9961ec1a986f0463de5c9c0 (patch)
tree9420686a2b0b1adb62734cf889734301136d93f1
parent414fa58ae9f283c35c8510fc31f28ba77bb5fdf5 (diff)
add support for new set API and standalone sets
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rwxr-xr-xfiles/examples/sets_and_maps53
-rw-r--r--include/expression.h20
-rw-r--r--include/linux/netfilter/nf_tables.h374
-rw-r--r--include/netlink.h16
-rw-r--r--include/rule.h67
-rw-r--r--src/evaluate.c284
-rw-r--r--src/expression.c42
-rw-r--r--src/netlink.c366
-rw-r--r--src/netlink_delinearize.c97
-rw-r--r--src/netlink_linearize.c70
-rw-r--r--src/parser.y291
-rw-r--r--src/rule.c178
-rw-r--r--src/scanner.l6
13 files changed, 1515 insertions, 349 deletions
diff --git a/files/examples/sets_and_maps b/files/examples/sets_and_maps
new file mode 100755
index 00000000..8dfe9f83
--- /dev/null
+++ b/files/examples/sets_and_maps
@@ -0,0 +1,53 @@
+#! /sbin/nft -nf
+#
+# Examples of set and map usage
+#
+
+# symbolic anonymous set definition built from symbolic singleton definitions
+define int_if1 = eth0
+define int_if2 = eth1
+define int_ifs = { $int_if1, $int_if2 }
+
+define ext_if1 = eth2
+define ext_if2 = eth3
+define ext_ifs = { $ext_if1, $ext_if2 }
+
+# recursive symbolic anonymous set definition
+define local_ifs = { $int_ifs, $ext_ifs }
+
+# symbolic anonymous set definition
+define tcp_ports = { ssh, domain, https, 123-125 }
+
+delete table filter
+table filter {
+ # named set of type ifindex
+ set local_ifs {
+ type ifindex
+ }
+
+ # named map of type ifindex => ipv4_address
+ map nat_map {
+ type ifindex => ipv4_address
+ }
+
+ map jump_map {
+ type ifindex => verdict
+ }
+
+ chain input_1 { counter; }
+ chain input_2 { counter; }
+ chain input {
+ hook NF_INET_LOCAL_IN 0
+
+ # symbolic anonymous sets
+ meta iif $local_ifs tcp dport $tcp_ports counter
+
+ # literal anonymous set
+ meta iif { eth0, eth1 } counter
+
+ meta iif @local_ifs counter
+ meta iif vmap @jump_map
+
+ #meta iif vmap { eth0 => jump input1, eth1 => jump input2 }
+ }
+}
diff --git a/include/expression.h b/include/expression.h
index 471033e7..88042846 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -26,6 +26,7 @@
* @EXPR_CONCAT: concatenation
* @EXPR_LIST: list of expressions
* @EXPR_SET: literal set
+ * @EXPR_SET_REF: set reference
* @EXPR_MAPPING: a single mapping (key => value)
* @EXPR_MAP: map operation (expr map { EXPR_MAPPING, ... })
* @EXPR_UNARY: byteorder conversion, generated during evaluation
@@ -46,6 +47,7 @@ enum expr_types {
EXPR_CONCAT,
EXPR_LIST,
EXPR_SET,
+ EXPR_SET_REF,
EXPR_MAPPING,
EXPR_MAP,
EXPR_UNARY,
@@ -82,6 +84,12 @@ enum ops {
extern const char *expr_op_symbols[];
+enum symbol_types {
+ SYMBOL_VALUE,
+ SYMBOL_DEFINE,
+ SYMBOL_SET,
+};
+
/**
* struct expr_ctx - type context for symbol parsing during evaluation
*
@@ -129,14 +137,12 @@ struct expr_ops {
* @EXPR_F_CONSTANT: constant expression
* @EXPR_F_SINGLETON: singleton (implies primary and constant)
* @EXPR_F_INTERVAL_END: set member ends an open interval
- * @SET_F_INTERVAL: set includes ranges and/or prefix expressions
*/
enum expr_flags {
EXPR_F_PRIMARY = 0x1,
EXPR_F_CONSTANT = 0x2,
EXPR_F_SINGLETON = 0x4,
EXPR_F_INTERVAL_END = 0x8,
- SET_F_INTERVAL = 0x10,
};
#include <payload.h>
@@ -176,6 +182,7 @@ struct expr {
/* EXPR_SYMBOL */
const struct scope *scope;
const char *identifier;
+ enum symbol_types symtype;
};
struct {
/* EXPR_VERDICT */
@@ -195,6 +202,11 @@ struct expr {
/* EXPR_CONCAT, EXPR_LIST, EXPR_SET */
struct list_head expressions;
unsigned int size;
+ uint32_t set_flags;
+ };
+ struct {
+ /* EXPR_SET_REF */
+ struct set *set;
};
struct {
/* EXPR_UNARY */
@@ -285,6 +297,7 @@ extern struct expr *verdict_expr_alloc(const struct location *loc,
int verdict, const char *chain);
extern struct expr *symbol_expr_alloc(const struct location *loc,
+ enum symbol_types type, struct scope *scope,
const char *identifier);
static inline void symbol_expr_set_type(struct expr *expr,
@@ -324,4 +337,7 @@ extern struct expr *mapping_expr_alloc(const struct location *loc,
extern struct expr *map_expr_alloc(const struct location *loc,
struct expr *arg, struct expr *list);
+extern struct expr *set_ref_expr_alloc(const struct location *loc,
+ struct set *set);
+
#endif /* NFTABLES_EXPRESSION_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 0309b9dc..1c230730 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -11,6 +11,17 @@ enum nft_registers {
};
#define NFT_REG_MAX (__NFT_REG_MAX - 1)
+/**
+ * enum nft_verdicts - nf_tables internal verdicts
+ *
+ * @NFT_CONTINUE: continue evaluation of the current rule
+ * @NFT_BREAK: terminate evaluation of the current rule
+ * @NFT_JUMP: push the current chain on the jump stack and jump to a chain
+ * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack
+ * @NFT_RETURN: return to the topmost chain on the jump stack
+ *
+ * The nf_tables verdicts share their numeric space with the netfilter verdicts.
+ */
enum nft_verdicts {
NFT_CONTINUE = -1,
NFT_BREAK = -2,
@@ -29,9 +40,20 @@ enum nf_tables_msg_types {
NFT_MSG_NEWRULE,
NFT_MSG_GETRULE,
NFT_MSG_DELRULE,
+ NFT_MSG_NEWSET,
+ NFT_MSG_GETSET,
+ NFT_MSG_DELSET,
+ NFT_MSG_NEWSETELEM,
+ NFT_MSG_GETSETELEM,
+ NFT_MSG_DELSETELEM,
NFT_MSG_MAX,
};
+/**
+ * enum nft_list_attributes - nf_tables generic list netlink attributes
+ *
+ * @NFTA_LIST_ELEM: list element (NLA_NESTED)
+ */
enum nft_list_attributes {
NFTA_LIST_UNPEC,
NFTA_LIST_ELEM,
@@ -39,6 +61,12 @@ enum nft_list_attributes {
};
#define NFTA_LIST_MAX (__NFTA_LIST_MAX - 1)
+/**
+ * enum nft_hook_attributes - nf_tables netfilter hook netlink attributes
+ *
+ * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ */
enum nft_hook_attributes {
NFTA_HOOK_UNSPEC,
NFTA_HOOK_HOOKNUM,
@@ -47,6 +75,11 @@ enum nft_hook_attributes {
};
#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
+/**
+ * enum nft_table_attributes - nf_tables table netlink attributes
+ *
+ * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
+ */
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
NFTA_TABLE_NAME,
@@ -54,6 +87,13 @@ enum nft_table_attributes {
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+/**
+ * enum nft_chain_attributes - nf_tables chain netlink attributes
+ *
+ * @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING)
+ * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
+ * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
+ */
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
NFTA_CHAIN_TABLE,
@@ -63,6 +103,14 @@ enum nft_chain_attributes {
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
+/**
+ * enum nft_rule_attributes - nf_tables rule netlink attributes
+ *
+ * @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING)
+ * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
+ * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U16)
+ * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
+ */
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
NFTA_RULE_TABLE,
@@ -73,6 +121,113 @@ enum nft_rule_attributes {
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
+/**
+ * enum nft_set_flags - nf_tables set flags
+ *
+ * @NFT_SET_ANONYMOUS: name allocation, automatic cleanup on unlink
+ * @NFT_SET_CONSTANT: set contents may not change while bound
+ * @NFT_SET_INTERVAL: set contains intervals
+ * @NFT_SET_MAP: set is used as a dictionary
+ */
+enum nft_set_flags {
+ NFT_SET_ANONYMOUS = 0x1,
+ NFT_SET_CONSTANT = 0x2,
+ NFT_SET_INTERVAL = 0x4,
+ NFT_SET_MAP = 0x8,
+};
+
+/**
+ * enum nft_set_attributes - nf_tables set netlink attributes
+ *
+ * @NFTA_SET_TABLE: table name (NLA_STRING)
+ * @NFTA_SET_NAME: set name (NLA_STRING)
+ * @NFTA_SET_FLAGS: bitmask of enum nft_set_flags (NLA_U32)
+ * @NFTA_SET_KEY_TYPE: key data type, informational purpose only (NLA_U32)
+ * @NFTA_SET_KEY_LEN: key data length (NLA_U32)
+ * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
+ * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
+ */
+enum nft_set_attributes {
+ NFTA_SET_UNSPEC,
+ NFTA_SET_TABLE,
+ NFTA_SET_NAME,
+ NFTA_SET_FLAGS,
+ NFTA_SET_KEY_TYPE,
+ NFTA_SET_KEY_LEN,
+ NFTA_SET_DATA_TYPE,
+ NFTA_SET_DATA_LEN,
+ __NFTA_SET_MAX
+};
+#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
+
+/**
+ * enum nft_set_elem_flags - nf_tables set element flags
+ *
+ * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ */
+enum nft_set_elem_flags {
+ NFT_SET_ELEM_INTERVAL_END = 0x1,
+};
+
+/**
+ * enum nft_set_elem_attributes - nf_tables set element netlink attributes
+ *
+ * @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
+ * @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
+ */
+enum nft_set_elem_attributes {
+ NFTA_SET_ELEM_UNSPEC,
+ NFTA_SET_ELEM_KEY,
+ NFTA_SET_ELEM_DATA,
+ NFTA_SET_ELEM_FLAGS,
+ __NFTA_SET_ELEM_MAX
+};
+#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
+
+/**
+ * enum nft_set_elem_list_attributes - nf_tables set element list netlink attributes
+ *
+ * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
+ */
+enum nft_set_elem_list_attributes {
+ NFTA_SET_ELEM_LIST_UNSPEC,
+ NFTA_SET_ELEM_LIST_TABLE,
+ NFTA_SET_ELEM_LIST_SET,
+ NFTA_SET_ELEM_LIST_ELEMENTS,
+ __NFTA_SET_ELEM_LIST_MAX
+};
+#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1)
+
+/**
+ * enum nft_data_types - nf_tables data types
+ *
+ * @NFT_DATA_VALUE: generic data
+ * @NFT_DATA_VERDICT: netfilter verdict
+ *
+ * The type of data is usually determined by the kernel directly and is not
+ * explicitly specified by userspace. The only difference are sets, where
+ * userspace specifies the key and mapping data types.
+ *
+ * The values 0xffffff00-0xffffffff are reserved for internally used types.
+ * The remaining range can be freely used by userspace to encode types, all
+ * values are equivalent to NFT_DATA_VALUE.
+ */
+enum nft_data_types {
+ NFT_DATA_VALUE,
+ NFT_DATA_VERDICT = 0xffffff00U,
+};
+
+#define NFT_DATA_RESERVED_MASK 0xffffff00U
+
+/**
+ * enum nft_data_attributes - nf_tables data netlink attributes
+ *
+ * @NFTA_DATA_VALUE: generic data (NLA_BINARY)
+ * @NFTA_DATA_VERDICT: nf_tables verdict (NLA_NESTED: nft_verdict_attributes)
+ */
enum nft_data_attributes {
NFTA_DATA_UNSPEC,
NFTA_DATA_VALUE,
@@ -81,6 +236,12 @@ enum nft_data_attributes {
};
#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1)
+/**
+ * enum nft_verdict_attributes - nf_tables verdict netlink attributes
+ *
+ * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
+ * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ */
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
@@ -89,6 +250,12 @@ enum nft_verdict_attributes {
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
+/**
+ * enum nft_expr_attributes - nf_tables expression netlink attributes
+ *
+ * @NFTA_EXPR_NAME: name of the expression type (NLA_STRING)
+ * @NFTA_EXPR_DATA: type specific data (NLA_NESTED)
+ */
enum nft_expr_attributes {
NFTA_EXPR_UNSPEC,
NFTA_EXPR_NAME,
@@ -97,6 +264,12 @@ enum nft_expr_attributes {
};
#define NFTA_EXPR_MAX (__NFTA_EXPR_MAX - 1)
+/**
+ * enum nft_immediate_attributes - nf_tables immediate expression netlink attributes
+ *
+ * @NFTA_IMMEDIATE_DREG: destination register to load data into (NLA_U32)
+ * @NFTA_IMMEDIATE_DATA: data to load (NLA_NESTED: nft_data_attributes)
+ */
enum nft_immediate_attributes {
NFTA_IMMEDIATE_UNSPEC,
NFTA_IMMEDIATE_DREG,
@@ -105,6 +278,27 @@ enum nft_immediate_attributes {
};
#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
+/**
+ * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
+ *
+ * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_DREG: destination register (NLA_U32: nft_registers)
+ * @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)
+ *
+ * The bitwise expression performs the following operation:
+ *
+ * dreg = (sreg & mask) ^ xor
+ *
+ * which allow to express all bitwise operations:
+ *
+ * mask xor
+ * NOT: 1 1
+ * OR: 0 x
+ * XOR: 1 x
+ * AND: x 0
+ */
enum nft_bitwise_attributes {
NFTA_BITWISE_UNSPEC,
NFTA_BITWISE_SREG,
@@ -141,6 +335,13 @@ enum nft_cmp_ops {
NFT_CMP_GTE,
};
+/**
+ * enum nft_cmp_attributes - nf_tables cmp expression netlink attributes
+ *
+ * @NFTA_CMP_SREG: source register of data to compare (NLA_U32: nft_registers)
+ * @NFTA_CMP_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_CMP_DATA: data to compare against (NLA_NESTED: nft_data_attributes)
+ */
enum nft_cmp_attributes {
NFTA_CMP_UNSPEC,
NFTA_CMP_SREG,
@@ -150,65 +351,36 @@ enum nft_cmp_attributes {
};
#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
-enum nft_set_elem_flags {
- NFT_SE_INTERVAL_END = 0x1,
-};
-
-enum nft_set_elem_attributes {
- NFTA_SE_UNSPEC,
- NFTA_SE_KEY,
- NFTA_SE_DATA,
- NFTA_SE_FLAGS,
- __NFTA_SE_MAX
-};
-#define NFTA_SE_MAX (__NFTA_SE_MAX - 1)
-
-enum nft_set_flags {
- NFT_SET_INTERVAL = 0x1,
- NFT_SET_MAP = 0x2,
-};
-
-enum nft_set_attributes {
- NFTA_SET_UNSPEC,
- NFTA_SET_FLAGS,
- NFTA_SET_SREG,
- NFTA_SET_DREG,
- NFTA_SET_KLEN,
- NFTA_SET_DLEN,
- NFTA_SET_ELEMENTS,
- __NFTA_SET_MAX
-};
-#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
-
-enum nft_hash_flags {
- NFT_HASH_MAP = 0x1,
-};
-
-enum nft_hash_elem_attributes {
- NFTA_HE_UNSPEC,
- NFTA_HE_KEY,
- NFTA_HE_DATA,
- __NFTA_HE_MAX
-};
-#define NFTA_HE_MAX (__NFTA_HE_MAX - 1)
-
-enum nft_hash_attributes {
- NFTA_HASH_UNSPEC,
- NFTA_HASH_FLAGS,
- NFTA_HASH_SREG,
- NFTA_HASH_DREG,
- NFTA_HASH_KLEN,
- NFTA_HASH_ELEMENTS,
- __NFTA_HASH_MAX
-};
-#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
-
+enum nft_lookup_attributes {
+ NFTA_LOOKUP_UNSPEC,
+ NFTA_LOOKUP_SET,
+ NFTA_LOOKUP_SREG,
+ NFTA_LOOKUP_DREG,
+ __NFTA_LOOKUP_MAX
+};
+#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
+
+/**
+ * enum nft_payload_bases - nf_tables payload expression offset bases
+ *
+ * @NFT_PAYLOAD_LL_HEADER: link layer header
+ * @NFT_PAYLOAD_NETWORK_HEADER: network header
+ * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
+ */
enum nft_payload_bases {
NFT_PAYLOAD_LL_HEADER,
NFT_PAYLOAD_NETWORK_HEADER,
NFT_PAYLOAD_TRANSPORT_HEADER,
};
+/**
+ * enum nft_payload_attributes - nf_tables payload expression netlink attributes
+ *
+ * @NFTA_PAYLOAD_DREG: destination register to load data into (NLA_U32: nft_registers)
+ * @NFTA_PAYLOAD_BASE: payload base (NLA_U32: nft_payload_bases)
+ * @NFTA_PAYLOAD_OFFSET: payload offset relative to base (NLA_U32)
+ * @NFTA_PAYLOAD_LEN: payload length (NLA_U32)
+ */
enum nft_payload_attributes {
NFTA_PAYLOAD_UNSPEC,
NFTA_PAYLOAD_DREG,
@@ -229,6 +401,25 @@ enum nft_exthdr_attributes {
};
#define NFTA_EXTHDR_MAX (__NFTA_EXTHDR_MAX - 1)
+/**
+ * enum nft_meta_keys - nf_tables meta expression keys
+ *
+ * @NFT_META_LEN: packet length (skb->len)
+ * @NFT_META_PROTOCOL: packet ethertype protocol (skb->protocol), invalid in OUTPUT
+ * @NFT_META_PRIORITY: packet priority (skb->priority)
+ * @NFT_META_MARK: packet mark (skb->mark)
+ * @NFT_META_IIF: packet input interface index (dev->ifindex)
+ * @NFT_META_OIF: packet output interface index (dev->ifindex)
+ * @NFT_META_IIFNAME: packet input interface name (dev->name)
+ * @NFT_META_OIFNAME: packet output interface name (dev->name)
+ * @NFT_META_IIFTYPE: packet input interface type (dev->type)
+ * @NFT_META_OIFTYPE: packet output interface type (dev->type)
+ * @NFT_META_SKUID: originating socket UID (fsuid)
+ * @NFT_META_SKGID: originating socket GID (fsgid)
+ * @NFT_META_NFTRACE: packet nftrace bit
+ * @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
+ * @NFT_META_SECMARK: packet secmark (skb->secmark)
+ */
enum nft_meta_keys {
NFT_META_LEN,
NFT_META_PROTOCOL,
@@ -247,6 +438,12 @@ enum nft_meta_keys {
NFT_META_SECMARK,
};
+/**
+ * enum nft_meta_attributes - nf_tables meta expression netlink attributes
+ *
+ * @NFTA_META_DREG: destination register (NLA_U32)
+ * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
+ */
enum nft_meta_attributes {
NFTA_META_UNSPEC,
NFTA_META_DREG,
@@ -255,6 +452,23 @@ enum nft_meta_attributes {
};
#define NFTA_META_MAX (__NFTA_META_MAX - 1)
+/**
+ * enum nft_ct_keys - nf_tables ct expression keys
+ *
+ * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
+ * @NFT_CT_DIRECTION: conntrack direction (enum ip_conntrack_dir)
+ * @NFT_CT_STATUS: conntrack status (bitmask of enum ip_conntrack_status)
+ * @NFT_CT_MARK: conntrack mark value
+ * @NFT_CT_SECMARK: conntrack secmark value
+ * @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_PROTOCOL: conntrack layer 4 protocol
+ * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
+ * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
+ */
enum nft_ct_keys {
NFT_CT_STATE,
NFT_CT_DIRECTION,
@@ -271,6 +485,13 @@ enum nft_ct_keys {
NFT_CT_PROTO_DST,
};
+/**
+ * enum nft_ct_attributes - nf_tables ct expression netlink attributes
+ *
+ * @NFTA_CT_DREG: destination register (NLA_U32)
+ * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
+ * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
+ */
enum nft_ct_attributes {
NFTA_CT_UNSPEC,
NFTA_CT_DREG,
@@ -280,6 +501,12 @@ enum nft_ct_attributes {
};
#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
+/**
+ * enum nft_limit_attributes - nf_tables limit expression netlink attributes
+ *
+ * @NFTA_LIMIT_RATE: refill rate (NLA_U64)
+ * @NFTA_LIMIT_DEPTH: bucket depth (NLA_U64)
+ */
enum nft_limit_attributes {
NFTA_LIMIT_UNSPEC,
NFTA_LIMIT_RATE,
@@ -288,6 +515,12 @@ enum nft_limit_attributes {
};
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
+/**
+ * enum nft_counter_attributes - nf_tables counter expression netlink attributes
+ *
+ * @NFTA_COUNTER_BYTES: number of bytes (NLA_U64)
+ * @NFTA_COUNTER_PACKETS: number of packets (NLA_U64)
+ */
enum nft_counter_attributes {
NFTA_COUNTER_UNSPEC,
NFTA_COUNTER_BYTES,
@@ -296,6 +529,14 @@ enum nft_counter_attributes {
};
#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1)
+/**
+ * enum nft_log_attributes - nf_tables log expression netlink attributes
+ *
+ * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
+ * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
+ * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
+ * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ */
enum nft_log_attributes {
NFTA_LOG_UNSPEC,
NFTA_LOG_GROUP,
@@ -306,11 +547,23 @@ enum nft_log_attributes {
};
#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
+/**
+ * enum nft_reject_types - nf_tables reject expression reject types
+ *
+ * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
+ * @NFT_REJECT_TCP_RST: reject using TCP RST
+ */
enum nft_reject_types {
NFT_REJECT_ICMP_UNREACH,
NFT_REJECT_TCP_RST,
};
+/**
+ * enum nft_reject_attributes - nf_tables reject expression netlink attributes
+ *
+ * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)
+ * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8)
+ */
enum nft_reject_attributes {
NFTA_REJECT_UNSPEC,
NFTA_REJECT_TYPE,
@@ -319,11 +572,26 @@ enum nft_reject_attributes {
};
#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
+/**
+ * enum nft_nat_types - nf_tables nat expression NAT types
+ *
+ * @NFT_NAT_SNAT: source NAT
+ * @NFT_NAT_DNAT: destination NAT
+ */
enum nft_nat_types {
NFT_NAT_SNAT,
NFT_NAT_DNAT,
};
+/**
+ * enum nft_nat_attributes - nf_tables nat expression netlink attributes
+ *
+ * @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
+ * @NFTA_NAT_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ */
enum nft_nat_attributes {
NFTA_NAT_UNSPEC,
NFTA_NAT_TYPE,
diff --git a/include/netlink.h b/include/netlink.h
index ec9a6142..22ef489c 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -16,10 +16,12 @@
*
* @msgs: message queue
* @list: list of parsed rules/chains/tables
+ * @set: current set
*/
struct netlink_ctx {
struct list_head *msgs;
struct list_head list;
+ struct set *set;
};
extern void netlink_dump_object(struct nl_object *obj);
@@ -28,6 +30,7 @@ extern struct nfnl_nft_table *alloc_nft_table(const struct handle *h);
extern struct nfnl_nft_chain *alloc_nft_chain(const struct handle *h);
extern struct nfnl_nft_rule *alloc_nft_rule(const struct handle *h);
extern struct nfnl_nft_expr *alloc_nft_expr(int (*init)(struct nfnl_nft_expr *));
+extern struct nfnl_nft_set *alloc_nft_set(const struct handle *h);
extern struct nfnl_nft_data *alloc_nft_data(const void *data, unsigned int len);
extern struct nfnl_nft_data *netlink_gen_data(const struct expr *expr);
@@ -68,4 +71,17 @@ extern int netlink_get_table(struct netlink_ctx *ctx, const struct handle *h);
extern int netlink_list_table(struct netlink_ctx *ctx, const struct handle *h);
extern int netlink_flush_table(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set);
+extern int netlink_delete_set(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_get_set(struct netlink_ctx *ctx, const struct handle *h);
+
+extern int netlink_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ const struct expr *expr);
+extern int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ const struct expr *expr);
+extern int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set);
+
#endif /* NFTABLES_NETLINK_H */
diff --git a/include/rule.h b/include/rule.h
index 01eeb210..97543072 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -6,17 +6,19 @@
#include <list.h>
/**
- * struct handle - handle for tables, chains and rules
+ * struct handle - handle for tables, chains, rules and sets
*
* @family: protocol family
* @table: table name
* @chain: chain name (chains and rules only)
+ * @set: set name (sets only)
* @handle: rule handle (rules only)
*/
struct handle {
int family;
const char *table;
const char *chain;
+ const char *set;
uint32_t handle;
};
@@ -61,12 +63,14 @@ extern struct symbol *symbol_lookup(const struct scope *scope,
* @list: list node
* @handle: table handle
* @chains: chains contained in the table
+ * @sets: sets contained in the table
*/
struct table {
struct list_head list;
struct handle handle;
struct scope scope;
struct list_head chains;
+ struct list_head sets;
};
extern struct table *table_alloc(void);
@@ -121,6 +125,53 @@ extern void rule_free(struct rule *rule);
extern void rule_print(const struct rule *rule);
/**
+ * enum set_flags
+ *
+ * @SET_F_CONSTANT: Set content is constant
+ * @SET_F_INTERVAL: set includes ranges and/or prefix expressions
+ */
+enum set_flags {
+ SET_F_ANONYMOUS = 0x1,
+ SET_F_CONSTANT = 0x2,
+ SET_F_INTERVAL = 0x4,
+ SET_F_MAP = 0x8,
+};
+
+/**
+ * struct set - nftables set
+ *
+ * @list: table set list node
+ * @handle: set handle
+ * @location: location the set was defined/declared at
+ * @refcnt: reference count
+ * @flags: bitmask of set flags
+ * @keytype: key data type
+ * @keylen: key length
+ * @datatype: mapping data type
+ * @datalen: mapping data len
+ * @init: initializer
+ */
+struct set {
+ struct list_head list;
+ struct handle handle;
+ struct location location;
+ unsigned int refcnt;
+ uint32_t flags;
+ const struct datatype *keytype;
+ unsigned int keylen;
+ const struct datatype *datatype;
+ unsigned int datalen;
+ struct expr *init;
+};
+
+extern struct set *set_alloc(const struct location *loc);
+extern struct set *set_get(struct set *set);
+extern void set_free(struct set *set);
+extern void set_add_hash(struct set *set, struct table *table);
+extern struct set *set_lookup(const struct table *table, const char *name);
+extern void set_print(const struct set *set);
+
+/**
* enum cmd_ops - command operations
*
* @CMD_INVALID: invalid
@@ -141,12 +192,18 @@ enum cmd_ops {
* enum cmd_obj - command objects
*
* @CMD_OBJ_INVALID: invalid
+ * @CMD_OBJ_SETELEM: set element(s)
+ * @CMD_OBJ_SET: set
+ * @CMD_OBJ_SETS: multiple sets
* @CMD_OBJ_RULE: rule
* @CMD_OBJ_CHAIN: chain
* @CMD_OBJ_TABLE: table
*/
enum cmd_obj {
CMD_OBJ_INVALID,
+ CMD_OBJ_SETELEM,
+ CMD_OBJ_SET,
+ CMD_OBJ_SETS,
CMD_OBJ_RULE,
CMD_OBJ_CHAIN,
CMD_OBJ_TABLE,
@@ -170,6 +227,8 @@ struct cmd {
struct handle handle;
union {
void *data;
+ struct expr *expr;
+ struct set *set;
struct rule *rule;
struct chain *chain;
struct table *table;
@@ -187,12 +246,18 @@ extern void cmd_free(struct cmd *cmd);
* struct eval_ctx - evaluation context
*
* @msgs: message queue
+ * @cmd: current command
+ * @table: current table
+ * @set: current set
* @stmt: current statement
* @ectx: expression context
* @pctx: payload context
*/
struct eval_ctx {
struct list_head *msgs;
+ struct cmd *cmd;
+ struct table *table;
+ struct set *set;
struct stmt *stmt;
struct expr_ctx ectx;
struct payload_ctx pctx;
diff --git a/src/evaluate.c b/src/evaluate.c
index ed3c688c..f3723779 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -52,6 +52,78 @@ static int __fmtstring(4, 5) stmt_binary_error(struct eval_ctx *ctx,
return -1;
}
+static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
+ const struct set *set,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, &set->location, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+ return -1;
+}
+
+static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
+ const struct datatype *keytype,
+ unsigned int keylen,
+ struct expr *expr)
+{
+ struct cmd *cmd;
+ struct set *set;
+
+ set = set_alloc(&expr->location);
+ set->flags = SET_F_CONSTANT | SET_F_ANONYMOUS | expr->set_flags;
+ set->handle.set = xstrdup(set->flags & SET_F_MAP ? "map%d" : "set%d");
+ set->keytype = keytype;
+ set->keylen = keylen;
+ set->init = expr;
+
+ if (ctx->table != NULL)
+ list_add_tail(&set->list, &ctx->table->sets);
+ else {
+ handle_merge(&set->handle, &ctx->cmd->handle);
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &set->handle, set);
+ cmd->location = set->location;
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ }
+
+ return set_ref_expr_alloc(&expr->location, set);
+}
+
+// FIXME
+#include <netlink.h>
+static struct set *get_set(struct eval_ctx *ctx, const struct handle *h,
+ const char *identifier)
+{
+ struct netlink_ctx nctx = {
+ .msgs = ctx->msgs,
+ };
+ struct handle handle;
+ struct set *set;
+ int err;
+
+ if (ctx->table != NULL) {
+ set = set_lookup(ctx->table, identifier);
+ if (set != NULL)
+ return set;
+ }
+
+ init_list_head(&nctx.list);
+
+ memset(&handle, 0, sizeof(handle));
+ handle_merge(&handle, h);
+ handle.set = xstrdup(identifier);
+ err = netlink_get_set(&nctx, &handle);
+ handle_free(&handle);
+
+ if (err < 0)
+ return NULL;
+ return list_first_entry(&nctx.list, struct set, list);
+}
+
static enum ops byteorder_conversion_op(struct expr *expr,
enum byteorder byteorder)
{
@@ -103,23 +175,32 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
{
struct error_record *erec;
struct symbol *sym;
+ struct set *set;
struct expr *new;
- (*expr)->dtype = ctx->ectx.dtype;
-
- if ((*expr)->scope != NULL) {
+ switch ((*expr)->symtype) {
+ case SYMBOL_VALUE:
+ (*expr)->dtype = ctx->ectx.dtype;
+ erec = symbol_parse(*expr, &new);
+ if (erec != NULL) {
+ erec_queue(erec, ctx->msgs);
+ return -1;
+ }
+ break;
+ case SYMBOL_DEFINE:
sym = symbol_lookup((*expr)->scope, (*expr)->identifier);
if (sym == NULL)
return expr_error(ctx, *expr,
"undefined identifier '%s'",
(*expr)->identifier);
new = expr_clone(sym->expr);
- } else {
- erec = symbol_parse(*expr, &new);
- if (erec != NULL) {
- erec_queue(erec, ctx->msgs);
+ break;
+ case SYMBOL_SET:
+ set = get_set(ctx, &ctx->cmd->handle, (*expr)->identifier);
+ if (set == NULL)
return -1;
- }
+ new = set_ref_expr_alloc(&(*expr)->location, set);
+ break;
}
expr_free(*expr);
@@ -548,10 +629,18 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
list_for_each_entry_safe(i, next, &set->expressions, list) {
if (list_member_evaluate(ctx, &i) < 0)
return -1;
+
if (!expr_is_constant(i))
return expr_error(ctx, i, "Set member is not constant");
- if (!expr_is_singleton(i))
- set->flags |= SET_F_INTERVAL;
+
+ if (i->ops->type == EXPR_SET) {
+ /* Merge recursive set definitions */
+ list_splice_tail_init(&i->expressions, &i->list);
+ list_del(&i->list);
+ set->set_flags |= i->set_flags;
+ expr_free(i);
+ } else if (!expr_is_singleton(i))
+ set->set_flags |= SET_F_INTERVAL;
}
set->dtype = ctx->ectx.dtype;
@@ -563,7 +652,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
{
struct expr_ctx ectx = ctx->ectx;
- struct expr *map = *expr, *i;
+ struct expr *map = *expr, *mappings;
if (expr_evaluate(ctx, &map->expr) < 0)
return -1;
@@ -571,39 +660,71 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx, map->expr,
"Map expression can not be constant");
- /* FIXME: segtree needs to know the dimension of the *key*.
- * The len should actually be the value of the mapping. */
- map->mappings->dtype = ctx->ectx.dtype;
- map->mappings->len = ctx->ectx.len;
+ mappings = map->mappings;
+ mappings->set_flags |= SET_F_MAP;
- list_for_each_entry(i, &map->mappings->expressions, list) {
- expr_set_context(&ctx->ectx, map->expr->dtype, map->expr->len);
- if (expr_evaluate(ctx, &i->left) < 0)
+ switch (map->mappings->ops->type) {
+ case EXPR_SET:
+ mappings = implicit_set_declaration(ctx, ctx->ectx.dtype,
+ ctx->ectx.len, mappings);
+ mappings->set->datatype = ectx.dtype;
+ mappings->set->datalen = ectx.len;
+
+ map->mappings = mappings;
+
+ ctx->set = mappings->set;
+ if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
return -1;
- if (!expr_is_constant(i->left))
- return expr_error(ctx, i->left,
- "Key must be a constant");
- if (!expr_is_singleton(i->left))
- map->mappings->flags |= SET_F_INTERVAL;
-
- expr_set_context(&ctx->ectx, ectx.dtype, ectx.len);
- if (expr_evaluate(ctx, &i->right) < 0)
+ ctx->set = NULL;
+ break;
+ case EXPR_SYMBOL:
+ if (expr_evaluate(ctx, &map->mappings) < 0)
return -1;
- if (!expr_is_constant(i->right))
- return expr_error(ctx, i->right,
- "Mapping must be a constant");
- if (!expr_is_singleton(i->right))
- return expr_error(ctx, i->right,
- "Mapping must be a singleton");
+ if (map->mappings->ops->type != EXPR_SET_REF)
+ return expr_error(ctx, map->mappings,
+ "Expression is not a map");
+ break;
+ default:
+ BUG();
}
map->dtype = ctx->ectx.dtype;
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
- if (map->mappings->flags & SET_F_INTERVAL &&
+ if (map->mappings->set_flags & SET_F_INTERVAL &&
byteorder_conversion(ctx, &map->expr, BYTEORDER_BIG_ENDIAN) < 0)
return -1;
+
+ return 0;
+}
+
+static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *mapping = *expr;
+ struct set *set = ctx->set;
+
+ if (set == NULL)
+ return expr_error(ctx, mapping, "mapping outside of map context");
+ if (!(set->flags & SET_F_MAP))
+ return set_error(ctx, set, "set is not a map");
+
+ expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+ if (expr_evaluate(ctx, &mapping->left) < 0)
+ return -1;
+ if (!expr_is_constant(mapping->left))
+ return expr_error(ctx, mapping->left, "Key must be a constant");
+ mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
+
+ expr_set_context(&ctx->ectx, set->datatype, set->datalen);
+ if (expr_evaluate(ctx, &mapping->right) < 0)
+ return -1;
+ if (!expr_is_constant(mapping->right))
+ return expr_error(ctx, mapping->right, "Value must be a constant");
+ if (!expr_is_singleton(mapping->right))
+ return expr_error(ctx, mapping->right, "Value must be a singleton");
+
+ mapping->flags |= EXPR_F_CONSTANT;
return 0;
}
@@ -719,6 +840,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
rel->op = OP_RANGE;
break;
case EXPR_SET:
+ case EXPR_SET_REF:
rel->op = OP_LOOKUP;
break;
case EXPR_LIST:
@@ -732,10 +854,21 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
switch (rel->op) {
case OP_LOOKUP:
+ /* A literal set expression implicitly declares the set */
+ if (right->ops->type == EXPR_SET)
+ right = rel->right =
+ implicit_set_declaration(ctx, left->dtype, left->len, right);
+ else if (left->dtype != right->dtype)
+ return expr_binary_error(ctx, right, left,
+ "datatype mismatch, expected %s, "
+ "set has type %s",
+ left->dtype->desc,
+ right->dtype->desc);
+
/* Data for range lookups needs to be in big endian order */
- if (right->flags & SET_F_INTERVAL &&
+ if (right->set->flags & SET_F_INTERVAL &&
byteorder_conversion(ctx, &rel->left,
- BYTEORDER_BIG_ENDIAN) < 0)
+ BYTEORDER_BIG_ENDIAN) < 0)
return -1;
left = rel->left;
break;
@@ -839,6 +972,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
switch ((*expr)->ops->type) {
case EXPR_SYMBOL:
return expr_evaluate_symbol(ctx, expr);
+ case EXPR_SET_REF:
+ return 0;
case EXPR_VALUE:
return expr_evaluate_value(ctx, expr);
case EXPR_VERDICT:
@@ -864,6 +999,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_set(ctx, expr);
case EXPR_MAP:
return expr_evaluate_map(ctx, expr);
+ case EXPR_MAPPING:
+ return expr_evaluate_mapping(ctx, expr);
case EXPR_RELATIONAL:
return expr_evaluate_relational(ctx, expr);
default:
@@ -879,6 +1016,7 @@ static int stmt_evaluate_expr(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
{
+ expr_set_context(&ctx->ectx, &verdict_type, 0);
if (expr_evaluate(ctx, &stmt->expr) < 0)
return -1;
@@ -962,6 +1100,52 @@ static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
}
}
+static int setelem_evaluate(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct set *set;
+
+ set = get_set(ctx, &ctx->cmd->handle, ctx->cmd->handle.set);
+ if (set == NULL)
+ return -1;
+
+ ctx->set = set;
+ expr_set_context(&ctx->ectx, set->keytype, set->keylen);
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+ ctx->set = NULL;
+ return 0;
+}
+
+static int set_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+ const char *type;
+
+ type = set->flags & SET_F_MAP ? "map" : "set";
+
+ if (set->keytype == NULL)
+ return set_error(ctx, set, "%s definition does not specify "
+ "key data type", type);
+
+ set->keylen = set->keytype->size;
+ if (set->keylen == 0)
+ return set_error(ctx, set, "unqualified key data type "
+ "specified in %s definition", type);
+
+ if (!(set->flags & SET_F_MAP))
+ return 0;
+
+ if (set->datatype == NULL)
+ return set_error(ctx, set, "map definition does not specify "
+ "mapping data type");
+
+ set->datalen = set->datatype->size;
+ if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
+ return set_error(ctx, set, "unqualified mapping data type "
+ "specified in map definition");
+
+ return 0;
+}
+
static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
{
struct stmt *stmt, *tstmt = NULL;
@@ -999,18 +1183,31 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
static int table_evaluate(struct eval_ctx *ctx, struct table *table)
{
struct chain *chain;
+ struct set *set;
+ ctx->table = table;
+ list_for_each_entry(set, &table->sets, list) {
+ handle_merge(&set->handle, &table->handle);
+ if (set_evaluate(ctx, set) < 0)
+ return -1;
+ }
list_for_each_entry(chain, &table->chains, list) {
handle_merge(&chain->handle, &table->handle);
if (chain_evaluate(ctx, chain) < 0)
return -1;
}
+ ctx->table = NULL;
return 0;
}
static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
+ case CMD_OBJ_SETELEM:
+ return setelem_evaluate(ctx, &cmd->expr);
+ case CMD_OBJ_SET:
+ handle_merge(&cmd->set->handle, &cmd->handle);
+ return set_evaluate(ctx, cmd->set);
case CMD_OBJ_RULE:
handle_merge(&cmd->rule->handle, &cmd->handle);
return rule_evaluate(ctx, cmd->rule);
@@ -1027,6 +1224,21 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
}
}
+static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_SETELEM:
+ return setelem_evaluate(ctx, &cmd->expr);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_RULE:
+ case CMD_OBJ_CHAIN:
+ case CMD_OBJ_TABLE:
+ return 0;
+ default:
+ BUG();
+ }
+}
+
static int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
{
#if TRACE
@@ -1035,10 +1247,12 @@ static int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
erec_print(stdout, erec); printf("\n\n");
#endif
+ ctx->cmd = cmd;
switch (cmd->op) {
case CMD_ADD:
return cmd_evaluate_add(ctx, cmd);
case CMD_DELETE:
+ return cmd_evaluate_delete(ctx, cmd);
case CMD_LIST:
case CMD_FLUSH:
return 0;
diff --git a/src/expression.c b/src/expression.c
index d854eb29..dffe7a8b 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -188,6 +188,7 @@ static void symbol_expr_print(const struct expr *expr)
static void symbol_expr_clone(struct expr *new, const struct expr *expr)
{
+ new->symtype = expr->symtype;
new->scope = expr->scope;
new->identifier = xstrdup(expr->identifier);
}
@@ -206,12 +207,15 @@ static const struct expr_ops symbol_expr_ops = {
};
struct expr *symbol_expr_alloc(const struct location *loc,
+ enum symbol_types type, struct scope *scope,
const char *identifier)
{
struct expr *expr;
expr = expr_alloc(loc, &symbol_expr_ops, &invalid_type,
BYTEORDER_INVALID, 0);
+ expr->symtype = type;
+ expr->scope = scope;
expr->identifier = xstrdup(identifier);
return expr;
}
@@ -702,14 +706,42 @@ static const struct expr_ops map_expr_ops = {
};
struct expr *map_expr_alloc(const struct location *loc, struct expr *arg,
- struct expr *list)
+ struct expr *mappings)
{
struct expr *expr;
- assert(list->ops->type == EXPR_SET);
- expr = expr_alloc(loc, &map_expr_ops, list->dtype,
- list->byteorder, list->len);
+ expr = expr_alloc(loc, &map_expr_ops, &invalid_type, BYTEORDER_INVALID, 0);
expr->expr = arg;
- expr->mappings = list;
+ expr->mappings = mappings;
+ return expr;
+}
+
+static void set_ref_expr_print(const struct expr *expr)
+{
+ if (expr->set->flags & SET_F_ANONYMOUS)
+ expr_print(expr->set->init);
+ else
+ printf("@%s", expr->set->handle.set);
+}
+
+static void set_ref_expr_destroy(struct expr *expr)
+{
+ set_free(expr->set);
+}
+
+static const struct expr_ops set_ref_expr_ops = {
+ .type = EXPR_SET_REF,
+ .name = "set reference",
+ .print = set_ref_expr_print,
+ .destroy = set_ref_expr_destroy,
+};
+
+struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, &set_ref_expr_ops, set->keytype, 0, 0);
+ expr->set = set_get(set);
+ expr->flags |= EXPR_F_CONSTANT;
return expr;
}
diff --git a/src/netlink.c b/src/netlink.c
index 8ef14011..37981542 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -15,6 +15,8 @@
#include <netlink/netfilter/nft_rule.h>
#include <netlink/netfilter/nft_expr.h>
#include <netlink/netfilter/nft_data.h>
+#include <netlink/netfilter/nft_setelem.h>
+#include <netlink/netfilter/nft_set.h>
#include <linux/netfilter/nf_tables.h>
#include <nftables.h>
@@ -30,10 +32,13 @@ static struct nl_sock *nf_sock;
static void __init netlink_open_sock(void)
{
- // FIXME: should be done dynamically by nft_set and based on set members
nlmsg_set_default_size(65536);
nf_sock = nl_socket_alloc();
+ if (nf_sock == NULL)
+ memory_allocation_error();
+
nfnl_connect(nf_sock);
+ nl_socket_set_nonblocking(nf_sock);
}
static void __exit netlink_close_sock(void)
@@ -123,6 +128,42 @@ struct nfnl_nft_expr *alloc_nft_expr(int (*init)(struct nfnl_nft_expr *))
return nle;
}
+struct nfnl_nft_set *alloc_nft_set(const struct handle *h)
+{
+ struct nfnl_nft_set *nls;
+
+ nls = nfnl_nft_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+ nfnl_nft_set_set_family(nls, h->family);
+ nfnl_nft_set_set_table(nls, h->table, strlen(h->table) + 1);
+ if (h->set != NULL)
+ nfnl_nft_set_set_name(nls, h->set, strlen(h->set) + 1);
+ return nls;
+}
+
+static struct nfnl_nft_setelem *alloc_nft_setelem(const struct expr *expr)
+{
+ struct nfnl_nft_setelem *nlse;
+
+ nlse = nfnl_nft_setelem_alloc();
+ if (nlse == NULL)
+ memory_allocation_error();
+
+ if (expr->ops->type == EXPR_VALUE || expr->flags & EXPR_F_INTERVAL_END)
+ nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr));
+ else {
+ assert(expr->ops->type == EXPR_MAPPING);
+ nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr->left));
+ nfnl_nft_setelem_set_data(nlse, netlink_gen_data(expr->right));
+ }
+
+ if (expr->flags & EXPR_F_INTERVAL_END)
+ nfnl_nft_setelem_set_flags(nlse, NFT_SET_ELEM_INTERVAL_END);
+
+ return nlse;
+}
+
struct nfnl_nft_data *alloc_nft_data(const void *data, unsigned int len)
{
struct nfnl_nft_data *nld;
@@ -585,3 +626,326 @@ int netlink_flush_table(struct netlink_ctx *ctx, const struct handle *h)
{
return netlink_flush_rules(ctx, h);
}
+
+static enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
+{
+ switch (dtype->type) {
+ case TYPE_VERDICT:
+ return NFT_DATA_VERDICT;
+ default:
+ return dtype->type;
+ }
+}
+
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
+{
+ switch (type) {
+ case NFT_DATA_VERDICT:
+ return &verdict_type;
+ default:
+ return datatype_lookup(type);
+ }
+}
+
+static void add_set_cb(struct nl_object *obj, void *arg)
+{
+ struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj;
+ struct netlink_ctx *ctx = arg;
+ struct set *set = ctx->set;
+
+#if TRACE
+ netlink_dump_object(OBJ_CAST(nls));
+#endif
+ set->handle.set = xstrdup(nfnl_nft_set_get_name(nls));
+}
+
+static int netlink_add_set_cb(struct nl_msg *msg, void *arg)
+{
+ return nl_msg_parse(msg, add_set_cb, arg);
+}
+
+int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set)
+{
+ struct nfnl_nft_set *nls;
+ int err;
+
+ nls = alloc_nft_set(h);
+ nfnl_nft_set_set_flags(nls, set->flags);
+ nfnl_nft_set_set_keytype(nls, dtype_map_to_kernel(set->keytype));
+ nfnl_nft_set_set_keylen(nls, set->keylen / BITS_PER_BYTE);
+ if (set->flags & NFT_SET_MAP) {
+ nfnl_nft_set_set_datatype(nls, dtype_map_to_kernel(set->datatype));
+ nfnl_nft_set_set_datalen(nls, set->datalen / BITS_PER_BYTE);
+ }
+#if TRACE
+ netlink_dump_object(OBJ_CAST(nls));
+#endif
+
+ ctx->set = set;
+ netlink_set_callback(netlink_add_set_cb, ctx);
+ err = nfnl_nft_set_add(nf_sock, nls, NLM_F_EXCL | NLM_F_ECHO);
+ if (err == 0)
+ err = nl_recvmsgs_default(nf_sock);
+ netlink_set_callback(NULL, NULL);
+ nfnl_nft_set_put(nls);
+ ctx->set = NULL;
+
+ if (err < 0)
+ netlink_io_error(ctx, NULL, "Could not add set: %s",
+ nl_geterror(err));
+ return err;
+}
+
+int netlink_delete_set(struct netlink_ctx *ctx, const struct handle *h)
+{
+ struct nfnl_nft_set *nls;
+ int err;
+
+ nls = alloc_nft_set(h);
+ err = nfnl_nft_set_delete(nf_sock, nls, 0);
+ nfnl_nft_set_put(nls);
+
+ if (err < 0)
+ netlink_io_error(ctx, NULL, "Could not delete set: %s",
+ nl_geterror(err));
+ return err;
+}
+
+static void list_set_cb(struct nl_object *obj, void *arg)
+{
+ struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj;
+ struct netlink_ctx *ctx = arg;
+ const struct datatype *keytype, *datatype;
+ uint32_t flags;
+ struct set *set;
+#if TRACE
+ netlink_dump_object(obj);
+#endif
+ if (!nfnl_nft_set_test_family(nls) ||
+ !nfnl_nft_set_test_table(nls) ||
+ !nfnl_nft_set_test_name(nls) ||
+ !nfnl_nft_set_test_keytype(nls) ||
+ !nfnl_nft_set_test_keylen(nls)) {
+ netlink_io_error(ctx, NULL, "Incomplete set received");
+ return;
+ }
+
+ keytype = dtype_map_from_kernel(nfnl_nft_set_get_keytype(nls));
+ if (keytype == NULL) {
+ netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
+ nfnl_nft_set_get_keytype(nls));
+ return;
+ }
+
+ flags = nfnl_nft_set_get_flags(nls);
+ if (flags & NFT_SET_MAP) {
+ datatype = dtype_map_from_kernel(nfnl_nft_set_get_datatype(nls));
+ if (datatype == NULL) {
+ netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
+ nfnl_nft_set_get_datatype(nls));
+ return;
+ }
+ } else
+ datatype = NULL;
+
+ set = set_alloc(&internal_location);
+ set->handle.family = nfnl_nft_set_get_family(nls);
+ set->handle.table = xstrdup(nfnl_nft_set_get_table(nls));
+ set->handle.set = xstrdup(nfnl_nft_set_get_name(nls));
+ set->keytype = keytype;
+ set->keylen = nfnl_nft_set_get_keylen(nls) * BITS_PER_BYTE;
+ set->flags = flags;
+ set->datatype = datatype;
+ set->datalen = nfnl_nft_set_get_datalen(nls) * BITS_PER_BYTE;
+ list_add_tail(&set->list, &ctx->list);
+}
+
+int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h)
+{
+ struct nl_cache *set_cache;
+ int err;
+
+ err = nfnl_nft_set_alloc_cache(nf_sock, h->family, h->table, &set_cache);
+ if (err < 0)
+ return netlink_io_error(ctx, NULL,
+ "Could not receive sets from kernel: %s",
+ nl_geterror(err));
+
+ nl_cache_foreach(set_cache, list_set_cb, ctx);
+ nl_cache_free(set_cache);
+ return 0;
+}
+
+static int netlink_get_set_cb(struct nl_msg *msg, void *arg)
+{
+ return nl_msg_parse(msg, list_set_cb, arg);
+}
+
+int netlink_get_set(struct netlink_ctx *ctx, const struct handle *h)
+{
+ struct nfnl_nft_set *nls;
+ int err;
+
+ nls = alloc_nft_set(h);
+#if TRACE
+ netlink_dump_object(OBJ_CAST(nls));
+#endif
+ netlink_set_callback(netlink_get_set_cb, ctx);
+ err = nfnl_nft_set_query(nf_sock, nls, 0);
+ if (err == 0)
+ err = nl_recvmsgs_default(nf_sock);
+ netlink_set_callback(NULL, NULL);
+
+ nfnl_nft_set_put(nls);
+
+ if (err < 0)
+ return netlink_io_error(ctx, NULL,
+ "Could not receive set from kernel: %s",
+ nl_geterror(err));
+ return err;
+}
+
+static int alloc_setelem_cache(const struct expr *set, struct nl_cache **res)
+{
+ struct nfnl_nft_setelem *nlse;
+ struct nl_cache *elements;
+ const struct expr *expr;
+ int err;
+
+ err = nl_cache_alloc_name("netfilter/nft_setelem", &elements);
+ if (err < 0)
+ return err;
+ list_for_each_entry(expr, &set->expressions, list) {
+ nlse = alloc_nft_setelem(expr);
+ nl_cache_add(elements, OBJ_CAST(nlse));
+ }
+ *res = elements;
+ return 0;
+}
+
+int netlink_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ const struct expr *expr)
+{
+ struct nfnl_nft_set *nls;
+ struct nl_cache *elements;
+ int err;
+
+ nls = alloc_nft_set(h);
+#if TRACE
+ netlink_dump_object(OBJ_CAST(nls));
+#endif
+ err = alloc_setelem_cache(expr, &elements);
+ if (err < 0)
+ goto out;
+ err = nfnl_nft_setelem_add(nf_sock, nls, elements, 0);
+ if (err < 0)
+ goto out;
+ err = nl_recvmsgs_default(nf_sock);
+out:
+ nfnl_nft_set_put(nls);
+ if (err < 0)
+ netlink_io_error(ctx, NULL, "Could not add set elements: %s",
+ nl_geterror(err));
+ return err;
+}
+
+int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ const struct expr *expr)
+{
+ struct nfnl_nft_set *nls;
+ struct nl_cache *elements;
+ int err;
+
+ nls = alloc_nft_set(h);
+ err = alloc_setelem_cache(expr, &elements);
+ if (err < 0)
+ goto out;
+ err = nfnl_nft_setelem_delete(nf_sock, nls, elements, 0);
+ if (err < 0)
+ goto out;
+ err = nl_recvmsgs_default(nf_sock);
+out:
+ nfnl_nft_set_put(nls);
+ if (err < 0)
+ netlink_io_error(ctx, NULL, "Could not delete set elements: %s",
+ nl_geterror(err));
+ return err;
+}
+
+static void list_setelem_cb(struct nl_object *obj, void *arg)
+{
+ struct nfnl_nft_setelem *nlse = nl_object_priv(obj);
+ struct nfnl_nft_data *nld;
+ struct netlink_ctx *ctx = arg;
+ struct set *set = ctx->set;
+ struct expr *expr, *data;
+ uint32_t flags;
+#if TRACE
+ netlink_dump_object(obj);
+#endif
+ if (!nfnl_nft_setelem_test_key(nlse)) {
+ netlink_io_error(ctx, NULL, "Incomplete set element received");
+ return;
+ }
+
+ nld = nfnl_nft_setelem_get_key(nlse);
+ flags = nfnl_nft_setelem_get_flags(nlse);
+
+ expr = netlink_alloc_value(&internal_location, nld);
+ expr->dtype = set->keytype;
+ expr->byteorder = set->keytype->byteorder;
+ if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+ if (flags & NFT_SET_ELEM_INTERVAL_END)
+ expr->flags |= EXPR_F_INTERVAL_END;
+ else if (nfnl_nft_setelem_test_data(nlse)) {
+ nld = nfnl_nft_setelem_get_data(nlse);
+
+ data = netlink_alloc_data(&internal_location, nld,
+ set->datatype->type == EXPR_VERDICT ?
+ NFT_REG_VERDICT : NFT_REG_1);
+ data->dtype = set->datatype;
+
+ expr = mapping_expr_alloc(&internal_location, expr, data);
+ }
+
+ compound_expr_add(set->init, expr);
+}
+
+extern void interval_map_decompose(struct expr *set);
+
+int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set)
+{
+ struct nl_cache *elements;
+ struct nfnl_nft_set *nls;
+ int err;
+
+ nls = alloc_nft_set(h);
+#if TRACE
+ netlink_dump_object(OBJ_CAST(nls));
+#endif
+ err = nfnl_nft_setelem_alloc_cache(nf_sock, nls, &elements);
+ if (err < 0)
+ goto out;
+ err = nl_recvmsgs_default(nf_sock);
+ if (err < 0)
+ goto out;
+
+ ctx->set = set;
+ set->init = set_expr_alloc(&internal_location);
+ nl_cache_foreach(elements, list_setelem_cb, ctx);
+ nl_cache_free(elements);
+ ctx->set = NULL;
+
+ if (set->flags & NFT_SET_INTERVAL)
+ interval_map_decompose(set->init);
+out:
+ nfnl_nft_set_put(nls);
+ if (err < 0)
+ netlink_io_error(ctx, NULL, "Could not receive set elements: %s",
+ nl_geterror(err));
+ return err;
+}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 4b559399..a511313e 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -19,6 +19,7 @@
struct netlink_parse_ctx {
struct list_head *msgs;
+ struct table *table;
struct rule *rule;
struct expr *registers[NFT_REG_MAX + 1];
};
@@ -132,91 +133,34 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
-struct netlink_data_ctx {
- const struct location *location;
- struct expr *expr;
- enum nft_registers dreg;
-};
-
-static void netlink_data_ctx_init(struct netlink_data_ctx *dctx,
- const struct location *loc,
- struct expr *expr, enum nft_registers dreg)
-{
- dctx->location = loc;
- dctx->expr = expr;
- dctx->dreg = dreg;
-}
-
-static void netlink_set_parse_data(struct nfnl_nft_data *data,
- enum nft_set_elem_flags flags,
- void *arg)
-{
- struct netlink_data_ctx *dctx = arg;
- struct expr *expr;
-
- assert(dctx->dreg != NFT_REG_VERDICT);
- expr = netlink_alloc_value(dctx->location, data);
- if (flags & NFT_SE_INTERVAL_END)
- expr->flags |= EXPR_F_INTERVAL_END;
- compound_expr_add(dctx->expr, expr);
-}
-
-static void netlink_set_parse_mapping(struct nfnl_nft_data *data,
- struct nfnl_nft_data *mapping,
- enum nft_set_elem_flags flags,
- void *arg)
-{
- struct netlink_data_ctx *dctx = arg;
- struct expr *expr, *left, *right;
-
- left = netlink_alloc_value(dctx->location, data);
- if (mapping != NULL) {
- right = netlink_alloc_data(dctx->location, mapping, dctx->dreg);
- expr = mapping_expr_alloc(dctx->location, left, right);
- } else
- expr = left;
-
- if (flags & NFT_SE_INTERVAL_END)
- expr->flags |= EXPR_F_INTERVAL_END;
- compound_expr_add(dctx->expr, expr);
-}
-
-extern void interval_map_decompose(struct expr *set);
-
-static void netlink_parse_set(struct netlink_parse_ctx *ctx,
- const struct location *loc,
- const struct nfnl_nft_expr *nle)
+static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nfnl_nft_expr *nle)
{
struct stmt *stmt;
struct expr *expr, *left, *right;
- struct netlink_data_ctx dctx;
+ struct set *set;
enum nft_registers dreg;
- enum nft_set_flags flags;
- left = netlink_get_register(ctx, loc, nfnl_nft_set_get_sreg(nle));
+ left = netlink_get_register(ctx, loc, nfnl_nft_lookup_get_sreg(nle));
if (left == NULL)
return netlink_error(ctx, loc,
- "Set expression has no left hand side");
+ "Lookup expression has no left hand side");
- right = set_expr_alloc(loc);
+ set = set_lookup(ctx->table, nfnl_nft_lookup_get_set(nle));
+ if (set == NULL)
+ return netlink_error(ctx, loc,
+ "Unknown set '%s' in lookup expression",
+ nfnl_nft_lookup_get_set(nle));
- flags = nfnl_nft_set_get_flags(nle);
- if (flags & NFT_SET_MAP) {
- dreg = nfnl_nft_set_get_dreg(nle);
- netlink_data_ctx_init(&dctx, loc, right, dreg);
- nfnl_nft_set_foreach_mapping(nle, netlink_set_parse_mapping,
- &dctx);
+ right = set_ref_expr_alloc(loc, set);
+ if (nfnl_nft_lookup_test_dreg(nle)) {
+ dreg = nfnl_nft_lookup_get_dreg(nle);
expr = map_expr_alloc(loc, left, right);
if (dreg != NFT_REG_VERDICT)
return netlink_set_register(ctx, dreg, expr);
} else {
- netlink_data_ctx_init(&dctx, loc, right, EXPR_VALUE);
- nfnl_nft_set_foreach_elem(nle, netlink_set_parse_data, &dctx);
- if (flags & NFT_SET_INTERVAL) {
- interval_map_decompose(right);
- right->flags |= NFT_SET_INTERVAL;
- }
expr = relational_expr_alloc(loc, OP_LOOKUP, left, right);
}
@@ -487,7 +431,7 @@ static const struct {
} netlink_parsers[] = {
{ .name = "immediate", .parse = netlink_parse_immediate },
{ .name = "cmp", .parse = netlink_parse_cmp },
- { .name = "set", .parse = netlink_parse_set },
+ { .name = "lookup", .parse = netlink_parse_lookup },
{ .name = "bitwise", .parse = netlink_parse_bitwise },
{ .name = "byteorder", .parse = netlink_parse_byteorder },
{ .name = "payload", .parse = netlink_parse_payload },
@@ -586,12 +530,6 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
switch (expr->ops->type) {
case EXPR_MAP:
expr_postprocess(ctx, stmt, &expr->expr);
- list_for_each_entry(i, &expr->mappings->expressions, list) {
- if (i->flags & EXPR_F_INTERVAL_END)
- continue;
- expr_set_type(i->left, expr->expr->dtype,
- expr->expr->byteorder);
- }
expr_postprocess(ctx, stmt, &expr->mappings);
break;
case EXPR_MAPPING:
@@ -682,6 +620,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
expr->len = len;
}
break;
+ case EXPR_SET_REF:
case EXPR_EXTHDR:
case EXPR_META:
case EXPR_CT:
@@ -734,6 +673,8 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
h.handle = nfnl_nft_rule_get_handle(nlr);
pctx->rule = rule_alloc(&internal_location, &h);
+ pctx->table = table_lookup(&h);
+ assert(pctx->table != NULL);
nfnl_nft_rule_foreach_expr(nlr, netlink_parse_expr, pctx);
rule_parse_postprocess(pctx, pctx->rule);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 65e4b69b..121dca15 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -105,17 +105,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
enum nft_registers dreg)
{
struct nfnl_nft_expr *nle;
- struct nfnl_nft_data *data;
- struct nfnl_nft_data *mapping;
- const struct expr *i;
- enum nft_set_elem_flags flags;
enum nft_registers sreg;
- unsigned int klen, dlen;
- assert(expr->mappings->ops->type == EXPR_SET);
+ assert(expr->mappings->ops->type == EXPR_SET_REF);
- klen = expr->expr->len / BITS_PER_BYTE;
- dlen = expr->mappings->len / BITS_PER_BYTE;
if (dreg == NFT_REG_VERDICT)
sreg = get_register(ctx);
else
@@ -123,38 +116,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
netlink_gen_expr(ctx, expr->expr, sreg);
- nle = alloc_nft_expr(nfnl_nft_set_init);
- nfnl_nft_set_set_flags(nle, NFT_SET_MAP);
- nfnl_nft_set_set_sreg(nle, sreg);
- nfnl_nft_set_set_klen(nle, klen);
- nfnl_nft_set_set_dreg(nle, dreg);
- nfnl_nft_set_set_dlen(nle, dlen);
-
- if (expr->mappings->flags & SET_F_INTERVAL) {
- set_to_intervals(expr->mappings);
- nfnl_nft_set_set_flags(nle, NFT_SET_INTERVAL);
- }
-
- list_for_each_entry(i, &expr->mappings->expressions, list) {
- flags = 0;
-
- switch (i->ops->type) {
- case EXPR_MAPPING:
- data = netlink_gen_data(i->left);
- mapping = netlink_gen_data(i->right);
- break;
- case EXPR_VALUE:
- assert(i->flags & EXPR_F_INTERVAL_END);
- data = netlink_gen_data(i);
- mapping = NULL;
- flags = NFT_SE_INTERVAL_END;
- break;
- default:
- BUG();
- }
-
- nfnl_nft_set_add_mapping(nle, data, mapping, flags);
- }
+ nle = alloc_nft_expr(nfnl_nft_lookup_init);
+ nfnl_nft_lookup_set_sreg(nle, sreg);
+ nfnl_nft_lookup_set_dreg(nle, dreg);
+ nfnl_nft_lookup_set_set(nle, expr->mappings->set->handle.set);
if (dreg == NFT_REG_VERDICT)
release_register(ctx);
@@ -167,34 +132,17 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
enum nft_registers dreg)
{
struct nfnl_nft_expr *nle;
- const struct expr *i;
- enum nft_set_elem_flags flags;
enum nft_registers sreg;
- assert(expr->right->ops->type == EXPR_SET);
+ assert(expr->right->ops->type == EXPR_SET_REF);
assert(dreg == NFT_REG_VERDICT);
sreg = get_register(ctx);
netlink_gen_expr(ctx, expr->left, sreg);
- nle = alloc_nft_expr(nfnl_nft_set_init);
- nfnl_nft_set_set_sreg(nle, sreg);
- nfnl_nft_set_set_klen(nle, expr->left->len / BITS_PER_BYTE);
-
- if (expr->right->flags & SET_F_INTERVAL) {
- set_to_intervals(expr->right);
- nfnl_nft_set_set_flags(nle, NFT_SET_INTERVAL);
- }
-
- list_for_each_entry(i, &expr->right->expressions, list) {
- assert(i->ops->type == EXPR_VALUE);
-
- flags = 0;
- if (i->flags & EXPR_F_INTERVAL_END)
- flags = NFT_SE_INTERVAL_END;
-
- nfnl_nft_set_add_elem(nle, netlink_gen_data(i), flags);
- }
+ nle = alloc_nft_expr(nfnl_nft_lookup_init);
+ nfnl_nft_lookup_set_sreg(nle, sreg);
+ nfnl_nft_lookup_set_set(nle, expr->right->set->handle.set);
release_register(ctx);
nfnl_nft_rule_add_expr(ctx->nlr, nle);
diff --git a/src/parser.y b/src/parser.y
index c63a14e0..419dcd72 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -119,6 +119,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
struct rule *rule;
struct stmt *stmt;
struct expr *expr;
+ struct set *set;
}
%token TOKEN_EOF 0 "end of file"
@@ -146,9 +147,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token DASH "-"
%token AT "@"
%token ARROW "=>"
-%token MAP "map"
%token VMAP "vmap"
-%token SET "set"
%token INCLUDE "include"
%token DEFINE "define"
@@ -158,6 +157,10 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token TABLE "table"
%token CHAIN "chain"
%token RULE "rule"
+%token SETS "sets"
+%token SET "set"
+%token ELEMENT "element"
+%token MAP "map"
%token HANDLE "handle"
%token ADD "add"
@@ -327,15 +330,23 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <handle> table_spec chain_spec chain_identifier ruleid_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec
+%type <handle> set_spec set_identifier
+%destructor { handle_free(&$$); } set_spec set_identifier
%type <val> handle_spec family_spec
%type <table> table_block_alloc table_block
%destructor { table_free($$); } table_block_alloc
-%type <chain> table_line chain_block_alloc chain_block
-%destructor { chain_free($$); } table_line chain_block_alloc
+%type <chain> chain_block_alloc chain_block
+%destructor { chain_free($$); } chain_block_alloc
%type <rule> rule
%destructor { rule_free($$); } rule
+%type <set> set_block_alloc set_block
+%destructor { set_free($$); } set_block_alloc
+
+%type <set> map_block_alloc map_block
+%destructor { set_free($$); } map_block_alloc
+
%type <list> stmt_list
%destructor { stmt_list_free($$); xfree($$); } stmt_list
%type <stmt> stmt match_stmt verdict_stmt
@@ -372,11 +383,11 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> concat_expr map_lhs_expr
%destructor { expr_free($$); } concat_expr map_lhs_expr
-%type <expr> map_expr map_list map_list_expr
-%destructor { expr_free($$); } map_expr map_list map_list_expr
+%type <expr> map_expr
+%destructor { expr_free($$); } map_expr
-%type <expr> verdict_map_expr verdict_map_list verdict_map_list_expr
-%destructor { expr_free($$); } verdict_map_expr verdict_map_list verdict_map_list_expr
+%type <expr> verdict_map_expr
+%destructor { expr_free($$); } verdict_map_expr
%type <expr> set_expr set_list_expr set_list_member_expr
%destructor { expr_free($$); } set_expr set_list_expr set_list_member_expr
@@ -384,10 +395,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> expr initializer_expr
%destructor { expr_free($$); } expr initializer_expr
-%type <expr> match_expr
-%destructor { expr_free($$); } match_expr
-%type <expr> relational_expr membership_expr
-%destructor { expr_free($$); } relational_expr membership_expr
+%type <expr> relational_expr
+%destructor { expr_free($$); } relational_expr
%type <val> relational_op
%type <expr> payload_expr payload_raw_expr
@@ -520,6 +529,24 @@ add_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$1, $2);
}
+ | SET set_spec set_block_alloc
+ '{' set_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, $5);
+ }
+ | MAP set_spec map_block_alloc
+ '{' map_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, $5);
+ }
+ | ELEMENT set_spec set_expr
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, $3);
+ }
;
delete_cmd : TABLE table_spec
@@ -534,6 +561,14 @@ delete_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, NULL);
}
+ | SET set_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, NULL);
+ }
+ | ELEMENT set_spec set_expr
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, $3);
+ }
;
list_cmd : TABLE table_spec
@@ -544,6 +579,14 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, NULL);
}
+ | SETS table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$2, NULL);
+ }
+ | SET set_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &$2, NULL);
+ }
;
flush_cmd : TABLE table_spec
@@ -554,6 +597,10 @@ flush_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &$2, NULL);
}
+ | SET set_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_SET, &$2, NULL);
+ }
;
table_block_alloc : /* empty */
@@ -566,20 +613,35 @@ table_block_alloc : /* empty */
table_block : /* empty */ { $$ = $<table>-1; }
| table_block common_block
| table_block stmt_seperator
- | table_block table_line stmt_seperator
+ | table_block CHAIN chain_identifier
+ chain_block_alloc '{' chain_block '}'
+ stmt_seperator
{
- list_add_tail(&$2->list, &$1->chains);
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ close_scope(state);
+ list_add_tail(&$4->list, &$1->chains);
$$ = $1;
}
- ;
-
-table_line : CHAIN chain_identifier chain_block_alloc
- '{' chain_block '}'
- {
- handle_merge(&$3->handle, &$2);
- handle_free(&$2);
- close_scope(state);
- $$ = $3;
+ | table_block SET set_identifier
+ set_block_alloc '{' set_block '}'
+ stmt_seperator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->sets);
+ $$ = $1;
+ }
+ | table_block MAP set_identifier
+ map_block_alloc '{' map_block '}'
+ stmt_seperator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->sets);
+ $$ = $1;
}
;
@@ -601,6 +663,59 @@ chain_block : /* empty */ { $$ = $<chain>-1; }
}
;
+set_block_alloc : /* empty */
+ {
+ $$ = set_alloc(NULL);
+ }
+ ;
+
+set_block : /* empty */ { $$ = $<set>-1; }
+ | set_block common_block
+ | set_block stmt_seperator
+ | set_block TYPE identifier stmt_seperator
+ {
+ $1->keytype = datatype_lookup_byname($3);
+ if ($1->keytype == NULL) {
+ erec_queue(error(&@3, "unknown datatype %s", $3),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+map_block_alloc : /* empty */
+ {
+ $$ = set_alloc(NULL);
+ $$->flags |= NFT_SET_MAP;
+ }
+ ;
+
+map_block : /* empty */ { $$ = $<set>-1; }
+ | map_block common_block
+ | map_block stmt_seperator
+ | map_block TYPE
+ identifier ARROW identifier
+ stmt_seperator
+ {
+ $1->keytype = datatype_lookup_byname($3);
+ if ($1->keytype == NULL) {
+ erec_queue(error(&@3, "unknown datatype %s", $3),
+ state->msgs);
+ YYERROR;
+ }
+
+ $1->datatype = datatype_lookup_byname($5);
+ if ($1->datatype == NULL) {
+ erec_queue(error(&@5, "unknown datatype %s", $5),
+ state->msgs);
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
hook_spec : HOOK HOOKNUM NUM
{
$<chain>0->hooknum = $2;
@@ -649,6 +764,20 @@ chain_identifier : identifier
}
;
+set_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.set = $2;
+ }
+ ;
+
+set_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.set = $1;
+ }
+ ;
+
handle_spec : /* empty */
{
$$ = 0;
@@ -806,7 +935,7 @@ nat_stmt_args : expr
}
;
-match_stmt : match_expr
+match_stmt : relational_expr
{
$$ = expr_stmt_alloc(&@$, $1);
}
@@ -814,13 +943,23 @@ match_stmt : match_expr
symbol_expr : string
{
- $$ = symbol_expr_alloc(&@$, $1);
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state),
+ $1);
xfree($1);
}
| '$' identifier
{
- $$ = symbol_expr_alloc(&@$, $2);
- $$->scope = current_scope(state);
+ $$ = symbol_expr_alloc(&@$, SYMBOL_DEFINE,
+ current_scope(state),
+ $2);
+ xfree($2);
+ }
+ | AT identifier
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_SET,
+ current_scope(state),
+ $2);
xfree($2);
}
;
@@ -830,7 +969,9 @@ integer_expr : NUM
char str[64];
snprintf(str, sizeof(str), "%" PRIu64, $1);
- $$ = symbol_expr_alloc(&@$, str);
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state),
+ str);
}
;
@@ -938,76 +1079,62 @@ map_lhs_expr : multiton_expr
| concat_expr
;
-map_expr : concat_expr MAP '{' map_list '}'
+map_expr : concat_expr MAP expr
{
- $$ = map_expr_alloc(&@$, $1, $4);
+ $$ = map_expr_alloc(&@$, $1, $3);
}
;
-map_list : map_list_expr
+verdict_map_expr : concat_expr VMAP expr
{
- $$ = set_expr_alloc(&@$);
- compound_expr_add($$, $1);
+ $$ = map_expr_alloc(&@$, $1, $3);
}
- | map_list COMMA map_list_expr
- {
- compound_expr_add($1, $3);
- $1->location = @$;
- $$ = $1;
- }
- | map_list COMMA opt_newline
;
-map_list_expr : opt_newline map_lhs_expr opt_newline
- ARROW opt_newline
- concat_expr opt_newline
- {
- $$ = mapping_expr_alloc(&@$, $2, $6);
- }
+expr : concat_expr
+ | set_expr
+ | map_expr
+ | multiton_expr
;
-verdict_map_expr : concat_expr VMAP '{' verdict_map_list '}'
+set_expr : '{' set_list_expr '}'
{
- $$ = map_expr_alloc(&@$, $1, $4);
+ $2->location = @$;
+ $$ = $2;
}
;
-verdict_map_list : verdict_map_list_expr
+set_list_expr : set_list_member_expr
{
$$ = set_expr_alloc(&@$);
compound_expr_add($$, $1);
}
- | verdict_map_list COMMA verdict_map_list_expr
+ | set_list_expr COMMA set_list_member_expr
{
compound_expr_add($1, $3);
- $1->location = @$;
$$ = $1;
}
- | verdict_map_list COMMA opt_newline
+ | set_list_expr COMMA opt_newline
;
-verdict_map_list_expr : opt_newline map_lhs_expr opt_newline
- ARROW opt_newline
- verdict_expr opt_newline
+set_list_member_expr : opt_newline expr opt_newline
{
- $$ = mapping_expr_alloc(&@$, $2, $6);
+ $$ = $2;
+ }
+ | opt_newline map_lhs_expr ARROW concat_expr opt_newline
+ {
+ $$ = mapping_expr_alloc(&@$, $2, $4);
+ }
+ | opt_newline map_lhs_expr ARROW verdict_expr opt_newline
+ {
+ $$ = mapping_expr_alloc(&@$, $2, $4);
}
- ;
-
-expr : concat_expr
- | map_expr
- | multiton_expr
;
initializer_expr : expr
- | set_expr
| list_expr
;
-match_expr : relational_expr
- | membership_expr
- ;
-
relational_expr : expr /* implicit */ expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
@@ -1030,38 +1157,6 @@ relational_op : EQ { $$ = OP_EQ; }
| LTE { $$ = OP_LTE; }
;
-membership_expr : expr set_expr
- {
- $$ = relational_expr_alloc(&@$, OP_LOOKUP, $1, $2);
- }
- ;
-
-set_expr : '{' set_list_expr '}'
- {
- $2->location = @$;
- $$ = $2;
- }
- ;
-
-set_list_expr : set_list_member_expr
- {
- $$ = set_expr_alloc(&@$);
- compound_expr_add($$, $1);
- }
- | set_list_expr COMMA set_list_member_expr
- {
- compound_expr_add($1, $3);
- $$ = $1;
- }
- | set_list_expr COMMA opt_newline
- ;
-
-set_list_member_expr : opt_newline expr opt_newline
- {
- $$ = $2;
- }
- ;
-
verdict_expr : ACCEPT
{
$$ = verdict_expr_alloc(&@$, NF_ACCEPT, NULL);
diff --git a/src/rule.c b/src/rule.c
index 6f322b8b..a5032cf7 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -23,6 +23,7 @@ void handle_free(struct handle *h)
{
xfree(h->table);
xfree(h->chain);
+ xfree(h->set);
}
void handle_merge(struct handle *dst, const struct handle *src)
@@ -33,10 +34,80 @@ void handle_merge(struct handle *dst, const struct handle *src)
dst->table = xstrdup(src->table);
if (dst->chain == NULL && src->chain != NULL)
dst->chain = xstrdup(src->chain);
+ if (dst->set == NULL && src->set != NULL)
+ dst->set = xstrdup(src->set);
if (dst->handle == 0)
dst->handle = src->handle;
}
+struct set *set_alloc(const struct location *loc)
+{
+ struct set *set;
+
+ set = xzalloc(sizeof(*set));
+ set->refcnt = 1;
+ if (loc != NULL)
+ set->location = *loc;
+ return set;
+}
+
+struct set *set_get(struct set *set)
+{
+ set->refcnt++;
+ return set;
+}
+
+void set_free(struct set *set)
+{
+ if (--set->refcnt > 0)
+ return;
+ handle_free(&set->handle);
+ xfree(set);
+}
+
+void set_add_hash(struct set *set, struct table *table)
+{
+ list_add_tail(&set->list, &table->sets);
+}
+
+struct set *set_lookup(const struct table *table, const char *name)
+{
+ struct set *set;
+
+ list_for_each_entry(set, &table->sets, list) {
+ if (!strcmp(set->handle.set, name))
+ return set;
+ }
+ return NULL;
+}
+
+void set_print(const struct set *set)
+{
+ const char *type;
+
+ type = set->flags & SET_F_MAP ? "map" : "set";
+ printf("\t%s %s {\n", type, set->handle.set);
+
+ printf("\t\ttype %s", set->keytype->name);
+ if (set->flags & SET_F_MAP)
+ printf(" => %s", set->datatype->name);
+ printf("\n");
+
+ if (set->flags & SET_F_ANONYMOUS)
+ printf("\t\tanonymous\n");
+ if (set->flags & SET_F_CONSTANT)
+ printf("\t\tconstant\n");
+ if (set->flags & SET_F_INTERVAL)
+ printf("\t\tinterval\n");
+
+ if (set->init != NULL && set->init->size > 0) {
+ printf("\t\telements = ");
+ expr_print(set->init);
+ printf("\n");
+ }
+ printf("\t}\n");
+}
+
struct rule *rule_alloc(const struct location *loc, const struct handle *h)
{
struct rule *rule;
@@ -168,6 +239,7 @@ struct table *table_alloc(void)
table = xzalloc(sizeof(*table));
init_list_head(&table->chains);
+ init_list_head(&table->sets);
return table;
}
@@ -204,9 +276,17 @@ struct table *table_lookup(const struct handle *h)
static void table_print(const struct table *table)
{
struct chain *chain;
+ struct set *set;
const char *delim = "";
printf("table %s {\n", table->handle.table);
+ list_for_each_entry(set, &table->sets, list) {
+ if (set->flags & SET_F_ANONYMOUS)
+ continue;
+ printf("%s", delim);
+ set_print(set);
+ delim = "\n";
+ }
list_for_each_entry(chain, &table->chains, list) {
printf("%s", delim);
chain_print(chain);
@@ -233,6 +313,12 @@ void cmd_free(struct cmd *cmd)
handle_free(&cmd->handle);
if (cmd->data != NULL) {
switch (cmd->obj) {
+ case CMD_OBJ_SETELEM:
+ expr_free(cmd->expr);
+ break;
+ case CMD_OBJ_SET:
+ set_free(cmd->set);
+ break;
case CMD_OBJ_RULE:
rule_free(cmd->rule);
break;
@@ -267,14 +353,42 @@ static int do_add_chain(struct netlink_ctx *ctx, const struct handle *h,
return 0;
}
+static int do_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ const struct expr *expr)
+{
+ if (netlink_add_setelems(ctx, h, expr) < 0)
+ return -1;
+ return 0;
+}
+
+static int do_add_set(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set)
+{
+ if (netlink_add_set(ctx, h, set) < 0)
+ return -1;
+ if (set->init != NULL) {
+ if (set->flags & SET_F_INTERVAL)
+ set_to_intervals(set->init);
+ if (do_add_setelems(ctx, &set->handle, set->init) < 0)
+ return -1;
+ }
+ return 0;
+}
+
static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
struct table *table)
{
struct chain *chain;
+ struct set *set;
if (netlink_add_table(ctx, h, table) < 0)
return -1;
if (table != NULL) {
+ list_for_each_entry(set, &table->sets, list) {
+ handle_merge(&set->handle, &table->handle);
+ if (do_add_set(ctx, &set->handle, set) < 0)
+ return -1;
+ }
list_for_each_entry(chain, &table->chains, list) {
if (do_add_chain(ctx, &chain->handle, chain) < 0)
return -1;
@@ -292,6 +406,10 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd)
return do_add_chain(ctx, &cmd->handle, cmd->chain);
case CMD_OBJ_RULE:
return netlink_add_rule(ctx, &cmd->handle, cmd->rule);
+ case CMD_OBJ_SET:
+ return do_add_set(ctx, &cmd->handle, cmd->set);
+ case CMD_OBJ_SETELEM:
+ return do_add_setelems(ctx, &cmd->handle, cmd->expr);
default:
BUG();
}
@@ -307,39 +425,76 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
return netlink_delete_chain(ctx, &cmd->handle);
case CMD_OBJ_RULE:
return netlink_delete_rule(ctx, &cmd->handle);
+ case CMD_OBJ_SET:
+ return netlink_delete_set(ctx, &cmd->handle);
+ case CMD_OBJ_SETELEM:
+ return netlink_delete_setelems(ctx, &cmd->handle, cmd->expr);
default:
BUG();
}
}
+static int do_list_sets(struct netlink_ctx *ctx, struct table *table)
+{
+ struct set *set, *nset;
+
+ if (netlink_list_sets(ctx, &table->handle) < 0)
+ return -1;
+
+ list_for_each_entry_safe(set, nset, &ctx->list, list) {
+ if (set->flags & SET_F_ANONYMOUS &&
+ netlink_get_setelems(ctx, &set->handle, set) < 0)
+ return -1;
+ list_move_tail(&set->list, &table->sets);
+ }
+ return 0;
+}
+
static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table;
struct chain *chain;
- struct rule *rule, *next;
+ struct rule *rule, *nrule;
+ struct set *set, *nset;
+
+ table = table_alloc();
+ handle_merge(&table->handle, &cmd->handle);
+ table_add_hash(table);
switch (cmd->obj) {
case CMD_OBJ_TABLE:
+ if (do_list_sets(ctx, table) < 0)
+ return -1;
if (netlink_list_table(ctx, &cmd->handle) < 0)
return -1;
break;
case CMD_OBJ_CHAIN:
+ if (do_list_sets(ctx, table) < 0)
+ return -1;
if (netlink_list_chain(ctx, &cmd->handle) < 0)
return -1;
break;
+ case CMD_OBJ_SETS:
+ if (netlink_list_sets(ctx, &cmd->handle) < 0)
+ return -1;
+ list_for_each_entry_safe(set, nset, &ctx->list, list)
+ list_move_tail(&set->list, &table->sets);
+ break;
+ case CMD_OBJ_SET:
+ if (netlink_get_set(ctx, &cmd->handle) < 0)
+ return -1;
+ list_for_each_entry(set, &ctx->list, list) {
+ if (netlink_get_setelems(ctx, &cmd->handle, set) < 0)
+ return -1;
+ set_print(set);
+ }
+ return 0;
default:
BUG();
}
- table = NULL;
- list_for_each_entry_safe(rule, next, &ctx->list, list) {
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
table = table_lookup(&rule->handle);
- if (table == NULL) {
- table = table_alloc();
- handle_merge(&table->handle, &rule->handle);
- table_add_hash(table);
- }
-
chain = chain_lookup(table, &rule->handle);
if (chain == NULL) {
chain = chain_alloc(rule->handle.chain);
@@ -349,10 +504,7 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
list_move_tail(&rule->list, &chain->rules);
}
- if (table != NULL)
- table_print(table);
- else
- printf("table %s does not exist\n", cmd->handle.table);
+ table_print(table);
return 0;
}
diff --git a/src/scanner.l b/src/scanner.l
index f8d018bb..de2373da 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -210,9 +210,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"$" { return '$'; }
"=" { return '='; }
"=>" { return ARROW; }
-"map" { return MAP; }
"vmap" { return VMAP; }
-"set" { return SET; }
"NF_INET_PRE_ROUTING" { yylval->val = NF_INET_PRE_ROUTING; return HOOKNUM; }
"NF_INET_LOCAL_IN" { yylval->val = NF_INET_LOCAL_IN; return HOOKNUM; }
@@ -229,6 +227,10 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"table" { return TABLE; }
"chain" { return CHAIN; }
"rule" { return RULE; }
+"sets" { return SETS; }
+"set" { return SET; }
+"element" { return ELEMENT; }
+"map" { return MAP; }
"handle" { return HANDLE; }
"accept" { return ACCEPT; }