aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáté Eckl <ecklm94@gmail.com>2018-05-28 03:15:33 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2018-06-01 03:46:15 -0400
commit554ced0a6e2946562c20d9fffdbaf2aa7da36b1b (patch)
tree183337776f85d8e10d2a23b7ddc49a59cc0502c7
parent7849958b51aa392e3592b6b8181db0baad979b0b (diff)
netfilter: nf_tables: add support for native socket matching
Now it can only match the transparent flag of an ip/ipv6 socket. Signed-off-by: Máté Eckl <ecklm94@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h25
-rw-r--r--net/netfilter/Kconfig9
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nft_socket.c143
4 files changed, 178 insertions, 0 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 9c71f024f9cc..3d46c82a5ebd 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -905,6 +905,31 @@ enum nft_rt_attributes {
905#define NFTA_RT_MAX (__NFTA_RT_MAX - 1) 905#define NFTA_RT_MAX (__NFTA_RT_MAX - 1)
906 906
907/** 907/**
908 * enum nft_socket_attributes - nf_tables socket expression netlink attributes
909 *
910 * @NFTA_SOCKET_KEY: socket key to match
911 * @NFTA_SOCKET_DREG: destination register
912 */
913enum nft_socket_attributes {
914 NFTA_SOCKET_UNSPEC,
915 NFTA_SOCKET_KEY,
916 NFTA_SOCKET_DREG,
917 __NFTA_SOCKET_MAX
918};
919#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
920
921/*
922 * enum nft_socket_keys - nf_tables socket expression keys
923 *
924 * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option_
925 */
926enum nft_socket_keys {
927 NFT_SOCKET_TRANSPARENT,
928 __NFT_SOCKET_MAX
929};
930#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
931
932/**
908 * enum nft_ct_keys - nf_tables ct expression keys 933 * enum nft_ct_keys - nf_tables ct expression keys
909 * 934 *
910 * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info) 935 * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 3ec8886850b2..276e1e32f44e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -613,6 +613,15 @@ config NFT_FIB_INET
613 The lookup will be delegated to the IPv4 or IPv6 FIB depending 613 The lookup will be delegated to the IPv4 or IPv6 FIB depending
614 on the protocol of the packet. 614 on the protocol of the packet.
615 615
616config NFT_SOCKET
617 tristate "Netfilter nf_tables socket match support"
618 depends on IPV6 || IPV6=n
619 select NF_SOCKET_IPV4
620 select NF_SOCKET_IPV6 if IPV6
621 help
622 This option allows matching for the presence or absence of a
623 corresponding socket and its attributes.
624
616if NF_TABLES_NETDEV 625if NF_TABLES_NETDEV
617 626
618config NF_DUP_NETDEV 627config NF_DUP_NETDEV
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 9b3434360d49..eec169555731 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_NFT_FIB) += nft_fib.o
102obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o 102obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o
103obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o 103obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o
104obj-$(CONFIG_NF_OSF) += nf_osf.o 104obj-$(CONFIG_NF_OSF) += nf_osf.o
105obj-$(CONFIG_NFT_SOCKET) += nft_socket.o
105 106
106# nf_tables netdev 107# nf_tables netdev
107obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o 108obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o
diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
new file mode 100644
index 000000000000..d86337068ecb
--- /dev/null
+++ b/net/netfilter/nft_socket.c
@@ -0,0 +1,143 @@
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>
8
9struct nft_socket {
10 enum nft_socket_keys key:8;
11 union {
12 enum nft_registers dreg:8;
13 };
14};
15
16static void nft_socket_eval(const struct nft_expr *expr,
17 struct nft_regs *regs,
18 const struct nft_pktinfo *pkt)
19{
20 const struct nft_socket *priv = nft_expr_priv(expr);
21 struct sk_buff *skb = pkt->skb;
22 struct sock *sk = skb->sk;
23 u32 *dest = &regs->data[priv->dreg];
24
25 if (!sk)
26 switch(nft_pf(pkt)) {
27 case NFPROTO_IPV4:
28 sk = nf_sk_lookup_slow_v4(nft_net(pkt), skb, nft_in(pkt));
29 break;
30#if IS_ENABLED(CONFIG_NF_SOCKET_IPV6)
31 case NFPROTO_IPV6:
32 sk = nf_sk_lookup_slow_v6(nft_net(pkt), skb, nft_in(pkt));
33 break;
34#endif
35 default:
36 WARN_ON_ONCE(1);
37 regs->verdict.code = NFT_BREAK;
38 return;
39 }
40
41 if(!sk) {
42 nft_reg_store8(dest, 0);
43 return;
44 }
45
46 /* So that subsequent socket matching not to require other lookups. */
47 skb->sk = sk;
48
49 switch(priv->key) {
50 case NFT_SOCKET_TRANSPARENT:
51 nft_reg_store8(dest, nf_sk_is_transparent(sk));
52 break;
53 default:
54 WARN_ON(1);
55 regs->verdict.code = NFT_BREAK;
56 }
57}
58
59static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
60 [NFTA_SOCKET_KEY] = { .type = NLA_U32 },
61 [NFTA_SOCKET_DREG] = { .type = NLA_U32 },
62};
63
64static int nft_socket_init(const struct nft_ctx *ctx,
65 const struct nft_expr *expr,
66 const struct nlattr * const tb[])
67{
68 struct nft_socket *priv = nft_expr_priv(expr);
69 unsigned int len;
70
71 if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
72 return -EINVAL;
73
74 switch(ctx->family) {
75 case NFPROTO_IPV4:
76#if IS_ENABLED(CONFIG_NF_SOCKET_IPV6)
77 case NFPROTO_IPV6:
78#endif
79 case NFPROTO_INET:
80 break;
81 default:
82 return -EOPNOTSUPP;
83 }
84
85 priv->key = ntohl(nla_get_u32(tb[NFTA_SOCKET_KEY]));
86 switch(priv->key) {
87 case NFT_SOCKET_TRANSPARENT:
88 len = sizeof(u8);
89 break;
90 default:
91 return -EOPNOTSUPP;
92 }
93
94 priv->dreg = nft_parse_register(tb[NFTA_SOCKET_DREG]);
95 return nft_validate_register_store(ctx, priv->dreg, NULL,
96 NFT_DATA_VALUE, len);
97}
98
99static int nft_socket_dump(struct sk_buff *skb,
100 const struct nft_expr *expr)
101{
102 const struct nft_socket *priv = nft_expr_priv(expr);
103
104 if (nla_put_u32(skb, NFTA_SOCKET_KEY, htonl(priv->key)))
105 return -1;
106 if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
107 return -1;
108 return 0;
109}
110
111static struct nft_expr_type nft_socket_type;
112static const struct nft_expr_ops nft_socket_ops = {
113 .type = &nft_socket_type,
114 .size = NFT_EXPR_SIZE(sizeof(struct nft_socket)),
115 .eval = nft_socket_eval,
116 .init = nft_socket_init,
117 .dump = nft_socket_dump,
118};
119
120static struct nft_expr_type nft_socket_type __read_mostly = {
121 .name = "socket",
122 .ops = &nft_socket_ops,
123 .policy = nft_socket_policy,
124 .maxattr = NFTA_SOCKET_MAX,
125 .owner = THIS_MODULE,
126};
127
128static int __init nft_socket_module_init(void)
129{
130 return nft_register_expr(&nft_socket_type);
131}
132
133static void __exit nft_socket_module_exit(void)
134{
135 nft_unregister_expr(&nft_socket_type);
136}
137
138module_init(nft_socket_module_init);
139module_exit(nft_socket_module_exit);
140
141MODULE_LICENSE("GPL");
142MODULE_AUTHOR("Máté Eckl");
143MODULE_DESCRIPTION("nf_tables socket match module");