=== Basic matching ===

eg.: `meta socket isset 1`

This matches when there is a socket with the destination ip address
assigned to it as local address.

The new keyword `isset` represents a boolean, and it can later be reused
for the pointer type meta attributes, where the attribute is not
necessarily present at the time these rules are evaluated. For example
sk_user_data, sk_security, etc.

=== Socket specific matching ===

`meta socket flags <flags>`

This would match when `meta socket isset` matches AND the given flags
are set on the socket.

Signed-off-by: Máté Eckl <ecklm94@gmail.com>
---
 include/linux/netfilter/nf_tables.h |  2 ++
 src/meta.c                          |  2 ++
 src/parser_bison.y                  | 15 ++++++++++++++-
 src/scanner.l                       |  2 ++
 4 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 517a39a..0719726 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -788,6 +788,7 @@ 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_SUBKEY_ISSET: boolean, the subkey is set
  */
 enum nft_meta_keys {
 	NFT_META_LEN,
@@ -816,6 +817,7 @@ enum nft_meta_keys {
 	NFT_META_CGROUP,
 	NFT_META_PRANDOM,
 	NFT_META_SECPATH,
+	NFT_META_SUBKEY_ISSET,
 };
 
 /**
diff --git a/src/meta.c b/src/meta.c
index 3012efa..7bbe4b1 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -439,6 +439,8 @@ static const struct meta_template meta_templates[] = {
 						BYTEORDER_BIG_ENDIAN), /* avoid conversion; doesn't have endianess */
 	[NFT_META_SECPATH]	= META_TEMPLATE("secpath", &boolean_type,
 						BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN),
+	[NFT_META_SUBKEY_ISSET]	= META_TEMPLATE("isset", &boolean_type,
+						1 , BYTEORDER_HOST_ENDIAN),
 };
 
 static bool meta_key_is_qualified(enum nft_meta_keys key)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 7238a94..ecccd06 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -181,6 +181,7 @@ int nft_lex(void *, void *, void *);
 %token DASH			"-"
 %token AT			"@"
 %token VMAP			"vmap"
+%token ISSET		"isset"
 
 %token INCLUDE			"include"
 %token DEFINE			"define"
@@ -400,6 +401,7 @@ int nft_lex(void *, void *, void *);
 %token IIFGROUP			"iifgroup"
 %token OIFGROUP			"oifgroup"
 %token CGROUP			"cgroup"
+%token SOCKET 			"socket"
 
 %token CLASSID			"classid"
 %token NEXTHOP			"nexthop"
@@ -689,7 +691,7 @@ int nft_lex(void *, void *, void *);
 
 %type <expr>			meta_expr
 %destructor { expr_free($$); }	meta_expr
-%type <val>			meta_key	meta_key_qualified	meta_key_unqualified	numgen_type
+%type <val>			meta_key	meta_key_qualified	meta_key_unqualified	meta_key_extended	meta_subkey	numgen_type
 
 %type <val>			nf_key_proto
 
@@ -3452,6 +3454,10 @@ meta_expr		:	META	meta_key
 
 				$$ = meta_expr_alloc(&@$, key);
 			}
+			|	META	meta_key_extended
+			{
+				$$ = meta_expr_alloc(&@$, $2);
+			}
 			;
 
 meta_key		:	meta_key_qualified
@@ -3486,6 +3492,13 @@ meta_key_unqualified	:	MARK		{ $$ = NFT_META_MARK; }
 			|       CGROUP		{ $$ = NFT_META_CGROUP; }
 			;
 
+meta_key_extended		:	SOCKET	meta_subkey { $$ = $2; }
+/*			|	SOCKET	FLAGS { $$ = NFT_META_SOCKET_FLAGS; }
+*/			;
+
+meta_subkey		:		ISSET { $$ = NFT_META_SUBKEY_ISSET; }
+			;
+
 meta_stmt		:	META	meta_key	SET	stmt_expr
 			{
 				$$ = meta_stmt_alloc(&@$, $2, $4);
diff --git a/src/scanner.l b/src/scanner.l
index 70366d1..1fe2424 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -231,6 +231,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "$"			{ return '$'; }
 "="			{ return '='; }
 "vmap"			{ return VMAP; }
+"isset"			{ return ISSET; }
 
 "include"		{ return INCLUDE; }
 "define"		{ return DEFINE; }
@@ -495,6 +496,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "iifgroup"		{ return IIFGROUP; }
 "oifgroup"		{ return OIFGROUP; }
 "cgroup"		{ return CGROUP; }
+"socket"		{ return SOCKET; }
 
 "classid"		{ return CLASSID; }
 "nexthop"		{ return NEXTHOP; }
