1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/module.h>
3 #include <linux/netfilter/nf_tables.h>
4 #include <net/netfilter/nf_tables.h>
5 #include <net/netfilter/nf_tables_core.h>
6 #include <net/netfilter/nf_socket.h>
7 #include <net/inet_sock.h>
11 enum nft_socket_keys key
:8;
13 enum nft_registers dreg
:8;
17 static void nft_socket_wildcard(const struct nft_pktinfo
*pkt
,
18 struct nft_regs
*regs
, struct sock
*sk
,
21 switch (nft_pf(pkt
)) {
23 nft_reg_store8(dest
, inet_sk(sk
)->inet_rcv_saddr
== 0);
25 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
27 nft_reg_store8(dest
, ipv6_addr_any(&sk
->sk_v6_rcv_saddr
));
31 regs
->verdict
.code
= NFT_BREAK
;
36 static void nft_socket_eval(const struct nft_expr
*expr
,
37 struct nft_regs
*regs
,
38 const struct nft_pktinfo
*pkt
)
40 const struct nft_socket
*priv
= nft_expr_priv(expr
);
41 struct sk_buff
*skb
= pkt
->skb
;
42 struct sock
*sk
= skb
->sk
;
43 u32
*dest
= ®s
->data
[priv
->dreg
];
45 if (sk
&& !net_eq(nft_net(pkt
), sock_net(sk
)))
51 sk
= nf_sk_lookup_slow_v4(nft_net(pkt
), skb
, nft_in(pkt
));
53 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
55 sk
= nf_sk_lookup_slow_v6(nft_net(pkt
), skb
, nft_in(pkt
));
60 regs
->verdict
.code
= NFT_BREAK
;
65 regs
->verdict
.code
= NFT_BREAK
;
70 case NFT_SOCKET_TRANSPARENT
:
71 nft_reg_store8(dest
, inet_sk_transparent(sk
));
74 if (sk_fullsock(sk
)) {
77 regs
->verdict
.code
= NFT_BREAK
;
81 case NFT_SOCKET_WILDCARD
:
82 if (!sk_fullsock(sk
)) {
83 regs
->verdict
.code
= NFT_BREAK
;
86 nft_socket_wildcard(pkt
, regs
, sk
, dest
);
90 regs
->verdict
.code
= NFT_BREAK
;
97 static const struct nla_policy nft_socket_policy
[NFTA_SOCKET_MAX
+ 1] = {
98 [NFTA_SOCKET_KEY
] = { .type
= NLA_U32
},
99 [NFTA_SOCKET_DREG
] = { .type
= NLA_U32
},
102 static int nft_socket_init(const struct nft_ctx
*ctx
,
103 const struct nft_expr
*expr
,
104 const struct nlattr
* const tb
[])
106 struct nft_socket
*priv
= nft_expr_priv(expr
);
109 if (!tb
[NFTA_SOCKET_DREG
] || !tb
[NFTA_SOCKET_KEY
])
112 switch(ctx
->family
) {
114 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
123 priv
->key
= ntohl(nla_get_u32(tb
[NFTA_SOCKET_KEY
]));
125 case NFT_SOCKET_TRANSPARENT
:
126 case NFT_SOCKET_WILDCARD
:
129 case NFT_SOCKET_MARK
:
136 priv
->dreg
= nft_parse_register(tb
[NFTA_SOCKET_DREG
]);
137 return nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
138 NFT_DATA_VALUE
, len
);
141 static int nft_socket_dump(struct sk_buff
*skb
,
142 const struct nft_expr
*expr
)
144 const struct nft_socket
*priv
= nft_expr_priv(expr
);
146 if (nla_put_u32(skb
, NFTA_SOCKET_KEY
, htonl(priv
->key
)))
148 if (nft_dump_register(skb
, NFTA_SOCKET_DREG
, priv
->dreg
))
153 static struct nft_expr_type nft_socket_type
;
154 static const struct nft_expr_ops nft_socket_ops
= {
155 .type
= &nft_socket_type
,
156 .size
= NFT_EXPR_SIZE(sizeof(struct nft_socket
)),
157 .eval
= nft_socket_eval
,
158 .init
= nft_socket_init
,
159 .dump
= nft_socket_dump
,
162 static struct nft_expr_type nft_socket_type __read_mostly
= {
164 .ops
= &nft_socket_ops
,
165 .policy
= nft_socket_policy
,
166 .maxattr
= NFTA_SOCKET_MAX
,
167 .owner
= THIS_MODULE
,
170 static int __init
nft_socket_module_init(void)
172 return nft_register_expr(&nft_socket_type
);
175 static void __exit
nft_socket_module_exit(void)
177 nft_unregister_expr(&nft_socket_type
);
180 module_init(nft_socket_module_init
);
181 module_exit(nft_socket_module_exit
);
183 MODULE_LICENSE("GPL");
184 MODULE_AUTHOR("Máté Eckl");
185 MODULE_DESCRIPTION("nf_tables socket match module");
186 MODULE_ALIAS_NFT_EXPR("socket");