diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 3395faf..31fd6f4 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1284,6 +1284,10 @@ enum nft_fib_flags {
 	NFTA_FIB_F_PRESENT	= 1 << 5,	/* check existence only */
 };
 
+enum nft_socket_flags {
+	NFTA_SOCKET_TRANSPARENT = (1<<0),
+};
+
 enum nft_ct_helper_attributes {
 	NFTA_CT_HELPER_UNSPEC,
 	NFTA_CT_HELPER_NAME,
diff --git a/include/statement.h b/include/statement.h
index de26549..84a8f3f 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -32,6 +32,13 @@ struct counter_stmt {
 
 extern struct stmt *counter_stmt_alloc(const struct location *loc);
 
+struct socket_stmt {
+	bool exists;
+	__u8 flags;
+};
+
+extern struct stmt *socket_stmt_alloc(const struct location *loc, bool exists, __u8 flags);
+
 struct exthdr_stmt {
 	struct expr			*expr;
 	struct expr			*val;
@@ -248,6 +255,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_EXTHDR:	extension header statement
  * @STMT_FLOW_OFFLOAD:	flow offload statement
  * @STMT_MAP:		map statement
+ * @STMT_SOCKET:	socket statement
  */
 enum stmt_types {
 	STMT_INVALID,
@@ -273,6 +281,7 @@ enum stmt_types {
 	STMT_EXTHDR,
 	STMT_FLOW_OFFLOAD,
 	STMT_MAP,
+	STMT_SOCKET,
 };
 
 /**
@@ -335,6 +344,7 @@ struct stmt {
 		struct objref_stmt	objref;
 		struct flow_stmt	flow;
 		struct map_stmt		map;
+		struct socket_stmt	socket;
 	};
 };
 
diff --git a/include/xt.h b/include/xt.h
index 753511e..5b29522 100644
--- a/include/xt.h
+++ b/include/xt.h
@@ -14,7 +14,7 @@ void xt_stmt_release(const struct stmt *stmt);
 void netlink_parse_target(struct netlink_parse_ctx *ctx,
 			  const struct location *loc,
 			  const struct nftnl_expr *nle);
-void netlink_parse_match(struct netlink_parse_ctx *ctx,
+void xt_netlink_parse_match(struct netlink_parse_ctx *ctx,
 			 const struct location *loc,
 			 const struct nftnl_expr *nle);
 void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
@@ -28,7 +28,7 @@ static inline void xt_stmt_release(const struct stmt *stmt) {}
 static inline void netlink_parse_target(struct netlink_parse_ctx *ctx,
 					const struct location *loc,
 					const struct nftnl_expr *nle) {}
-static inline void netlink_parse_match(struct netlink_parse_ctx *ctx,
+static inline void xt_netlink_parse_match(struct netlink_parse_ctx *ctx,
 				       const struct location *loc,
 				       const struct nftnl_expr *nle) {}
 static inline void stmt_xt_postprocess(struct rule_pp_ctx *rctx,
diff --git a/src/evaluate.c b/src/evaluate.c
index 4eb36e2..5222f4e 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2686,6 +2686,15 @@ static int stmt_evaluate_objref(struct eval_ctx *ctx, struct stmt *stmt)
 	return 0;
 }
 
+static int stmt_evaluate_socket(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	const struct socket_stmt * const s = &stmt->socket;
+
+	if (!s->exists && s->flags)
+		return -1;
+	return 0;
+}
+
 int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 {
 	if (ctx->debug_mask & NFT_DEBUG_EVALUATION) {
@@ -2737,6 +2746,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 		return stmt_evaluate_objref(ctx, stmt);
 	case STMT_MAP:
 		return stmt_evaluate_map(ctx, stmt);
+	case STMT_SOCKET:
+		return stmt_evaluate_socket(ctx, stmt);
 	default:
 		BUG("unknown statement type %s\n", stmt->ops->name);
 	}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 8f4035a..19c753a 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -27,6 +27,7 @@
 #include <sys/socket.h>
 #include <libnftnl/udata.h>
 #include <xt.h>
+#include <linux/netfilter/xt_socket.h>
 
 static int netlink_parse_expr(const struct nftnl_expr *nle,
 			      struct netlink_parse_ctx *ctx);
@@ -1278,6 +1279,24 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
 	ctx->stmt = stmt;
 }
 
+static void netlink_parse_match(struct netlink_parse_ctx *ctx,
+				 const struct location *loc,
+				 const struct nftnl_expr *nle)
+{
+	if (!strcmp(nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME), "socket") &&
+	    nftnl_expr_get_u32(nle, NFTNL_EXPR_MT_REV) == 3) {
+		const struct xt_socket_mtinfo3 *info;
+		uint32_t len = 0;
+
+		info = nftnl_expr_get(nle, NFTNL_EXPR_MT_INFO, &len);
+		if(!info)
+			return;
+		ctx->stmt = socket_stmt_alloc(loc, true, info->flags); // true is placeholder
+	} else {
+		xt_netlink_parse_match(ctx, loc, nle);
+	}
+}
+
 static const struct {
 	const char	*name;
 	void		(*parse)(struct netlink_parse_ctx *ctx,
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 2ab8acc..5e9345a 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -19,6 +19,7 @@
 #include <gmputil.h>
 #include <utils.h>
 #include <netinet/in.h>
+#include <linux/netfilter/xt_socket.h>
 
 #include <linux/netfilter.h>
 #include <libnftnl/udata.h>
@@ -1155,6 +1156,24 @@ static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
 	nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_socket_match_stmt(struct netlink_linearize_ctx *ctx,
+					  const struct stmt *stmt)
+{
+	struct nftnl_expr *nle = alloc_nft_expr("match");
+	struct xt_socket_mtinfo3 *info;
+
+	nftnl_expr_set_str(nle, NFTNL_EXPR_MT_NAME, "socket");
+	nftnl_expr_set_u32(nle, NFTNL_EXPR_MT_REV, 3);
+
+	info = xzalloc(sizeof(struct xt_socket_mtinfo3));
+	info->flags = stmt->socket.flags;
+
+	nftnl_expr_set(nle, NFTNL_EXPR_MT_INFO, info, sizeof(struct xt_socket_mtinfo3));
+
+	nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
+
 static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
 				 const struct stmt *stmt)
 {
@@ -1283,6 +1302,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
 		return netlink_gen_objref_stmt(ctx, stmt);
 	case STMT_MAP:
 		return netlink_gen_map_stmt(ctx, stmt);
+	case STMT_SOCKET:
+		return netlink_gen_socket_match_stmt(ctx, stmt);
 	default:
 		BUG("unknown statement type %s\n", stmt->ops->name);
 	}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 0e3ee84..67a5b6f 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -189,6 +189,9 @@ int nft_lex(void *, void *, void *);
 
 %token FIB			"fib"
 
+%token SOCKET			"socket"
+%token TRANSPARENT		"transparent"
+
 %token HOOK			"hook"
 %token DEVICE			"device"
 %token DEVICES			"devices"
@@ -547,8 +550,11 @@ int nft_lex(void *, void *, void *);
 
 %type <list>			stmt_list
 %destructor { stmt_list_free($$); xfree($$); } stmt_list
-%type <stmt>			stmt match_stmt verdict_stmt
-%destructor { stmt_free($$); }	stmt match_stmt verdict_stmt
+%type <stmt>			stmt match_stmt verdict_stmt	socket_stmt
+%destructor { stmt_free($$); }	stmt match_stmt verdict_stmt	socket_stmt
+
+%type <val>			socket_stmt_flag socket_stmt_flags
+
 %type <stmt>			counter_stmt counter_stmt_alloc
 %destructor { stmt_free($$); }	counter_stmt counter_stmt_alloc
 %type <stmt>			payload_stmt
@@ -2078,6 +2084,27 @@ stmt			:	verdict_stmt
 			|	fwd_stmt
 			|	set_stmt
 			|	map_stmt
+			|	socket_stmt
+			;
+
+socket_stmt_flag	:	TRANSPARENT { $$ = NFTA_SOCKET_TRANSPARENT; }
+			;
+
+socket_stmt_flags	:	socket_stmt_flags COMMA socket_stmt_flag
+			{
+				$$ = $1 | $3;
+			}
+			|	socket_stmt_flag
+			;
+
+socket_stmt		:	SOCKET	EXISTS /* with the actual implementation we cannot match abscence */
+			{
+				$$ = socket_stmt_alloc(&@$, true, 0);
+			}
+			|	SOCKET FLAGS socket_stmt_flags /* we suppose existance criterion in this case */
+			{
+				$$ = socket_stmt_alloc(&@$, true, $3);
+			}
 			;
 
 verdict_stmt		:	verdict_expr
diff --git a/src/scanner.l b/src/scanner.l
index 6a861cf..416bd27 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -258,6 +258,9 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "ruleset"		{ return RULESET; }
 "trace"			{ return TRACE; }
 
+"socket"		{ return SOCKET; }
+"transparent"		{ return TRANSPARENT;}
+
 "accept"		{ return ACCEPT; }
 "drop"			{ return DROP; }
 "continue"		{ return CONTINUE; }
diff --git a/src/statement.c b/src/statement.c
index d291001..ff6a98a 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -176,6 +176,40 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
 	return stmt;
 }
 
+static void socket_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+	const struct socket_stmt *s = &stmt->socket;
+	const char *transp_str = "transparent",
+	     *existance_str = (s->exists) ? "exists" : "missing";
+
+	nft_print(octx, "socket");
+	if (s->flags) {
+		__u8 f = s->flags;
+
+		nft_print(octx, " flags ");
+		if(f & NFTA_SOCKET_TRANSPARENT)
+			nft_print(octx, "%s", transp_str);
+	} else {
+		nft_print(octx, " %s", existance_str);
+	}
+	// (!s->exists && s->flags) is impossible, see stmt_evaluate_socket
+}
+
+static const struct stmt_ops socket_stmt_ops = {
+	.type		= STMT_SOCKET,
+	.name		= "socket",
+	.print		= socket_stmt_print,
+};
+
+extern struct stmt *socket_stmt_alloc(const struct location *loc, bool exists, __u8 flags)
+{
+	struct stmt *stmt = stmt_alloc(loc, &socket_stmt_ops);
+
+	stmt->socket.exists = exists;
+	stmt->socket.flags = flags;
+	return stmt;
+}
+
 static const char *objref_type[NFT_OBJECT_MAX + 1] = {
 	[NFT_OBJECT_COUNTER]	= "counter",
 	[NFT_OBJECT_QUOTA]	= "quota",
diff --git a/src/xt.c b/src/xt.c
index 95d0c5f..4f7c235 100644
--- a/src/xt.c
+++ b/src/xt.c
@@ -188,7 +188,7 @@ static struct xtables_match *xt_match_clone(struct xtables_match *m)
  * Delinearization
  */
 
-void netlink_parse_match(struct netlink_parse_ctx *ctx,
+void xt_netlink_parse_match(struct netlink_parse_ctx *ctx,
 			 const struct location *loc,
 			 const struct nftnl_expr *nle)
 {
