aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c44
-rw-r--r--net/ipv4/netfilter/nf_tables_arp.c44
-rw-r--r--net/ipv4/netfilter/nf_tables_ipv4.c60
-rw-r--r--net/ipv4/netfilter/nft_chain_nat_ipv4.c10
-rw-r--r--net/ipv4/netfilter/nft_chain_route_ipv4.c10
-rw-r--r--net/ipv6/netfilter/nf_tables_ipv6.c65
-rw-r--r--net/ipv6/netfilter/nft_chain_nat_ipv6.c10
-rw-r--r--net/ipv6/netfilter/nft_chain_route_ipv6.c10
-rw-r--r--net/netfilter/Kconfig8
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_tables_api.c223
-rw-r--r--net/netfilter/nf_tables_core.c6
-rw-r--r--net/netfilter/nf_tables_inet.c104
-rw-r--r--net/netfilter/nft_compat.c8
-rw-r--r--net/netfilter/nft_ct.c199
-rw-r--r--net/netfilter/nft_log.c2
-rw-r--r--net/netfilter/nft_meta.c11
-rw-r--r--net/netfilter/nft_reject.c9
18 files changed, 547 insertions, 277 deletions
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c
index cf54b22818c8..5bcc0d8b31f2 100644
--- a/net/bridge/netfilter/nf_tables_bridge.c
+++ b/net/bridge/netfilter/nf_tables_bridge.c
@@ -14,10 +14,30 @@
14#include <linux/netfilter_bridge.h> 14#include <linux/netfilter_bridge.h>
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16 16
17static unsigned int
18nft_do_chain_bridge(const struct nf_hook_ops *ops,
19 struct sk_buff *skb,
20 const struct net_device *in,
21 const struct net_device *out,
22 int (*okfn)(struct sk_buff *))
23{
24 struct nft_pktinfo pkt;
25
26 nft_set_pktinfo(&pkt, ops, skb, in, out);
27
28 return nft_do_chain(&pkt, ops);
29}
30
17static struct nft_af_info nft_af_bridge __read_mostly = { 31static struct nft_af_info nft_af_bridge __read_mostly = {
18 .family = NFPROTO_BRIDGE, 32 .family = NFPROTO_BRIDGE,
19 .nhooks = NF_BR_NUMHOOKS, 33 .nhooks = NF_BR_NUMHOOKS,
20 .owner = THIS_MODULE, 34 .owner = THIS_MODULE,
35 .nops = 1,
36 .hooks = {
37 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
38 [NF_BR_FORWARD] = nft_do_chain_bridge,
39 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
40 },
21}; 41};
22 42
23static int nf_tables_bridge_init_net(struct net *net) 43static int nf_tables_bridge_init_net(struct net *net)
@@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_bridge_net_ops = {
48 .exit = nf_tables_bridge_exit_net, 68 .exit = nf_tables_bridge_exit_net,
49}; 69};
50 70
51static unsigned int 71static const struct nf_chain_type filter_bridge = {
52nft_do_chain_bridge(const struct nf_hook_ops *ops,
53 struct sk_buff *skb,
54 const struct net_device *in,
55 const struct net_device *out,
56 int (*okfn)(struct sk_buff *))
57{
58 struct nft_pktinfo pkt;
59
60 nft_set_pktinfo(&pkt, ops, skb, in, out);
61
62 return nft_do_chain_pktinfo(&pkt, ops);
63}
64
65static struct nf_chain_type filter_bridge = {
66 .family = NFPROTO_BRIDGE,
67 .name = "filter", 72 .name = "filter",
68 .type = NFT_CHAIN_T_DEFAULT, 73 .type = NFT_CHAIN_T_DEFAULT,
74 .family = NFPROTO_BRIDGE,
75 .owner = THIS_MODULE,
69 .hook_mask = (1 << NF_BR_LOCAL_IN) | 76 .hook_mask = (1 << NF_BR_LOCAL_IN) |
70 (1 << NF_BR_FORWARD) | 77 (1 << NF_BR_FORWARD) |
71 (1 << NF_BR_LOCAL_OUT), 78 (1 << NF_BR_LOCAL_OUT),
72 .fn = {
73 [NF_BR_LOCAL_IN] = nft_do_chain_bridge,
74 [NF_BR_FORWARD] = nft_do_chain_bridge,
75 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
76 },
77}; 79};
78 80
79static int __init nf_tables_bridge_init(void) 81static int __init nf_tables_bridge_init(void)
diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c
index 3e67ef1c676f..19412a4063fb 100644
--- a/net/ipv4/netfilter/nf_tables_arp.c
+++ b/net/ipv4/netfilter/nf_tables_arp.c
@@ -14,10 +14,30 @@
14#include <linux/netfilter_arp.h> 14#include <linux/netfilter_arp.h>
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16 16
17static unsigned int
18nft_do_chain_arp(const struct nf_hook_ops *ops,
19 struct sk_buff *skb,
20 const struct net_device *in,
21 const struct net_device *out,
22 int (*okfn)(struct sk_buff *))
23{
24 struct nft_pktinfo pkt;
25
26 nft_set_pktinfo(&pkt, ops, skb, in, out);
27
28 return nft_do_chain(&pkt, ops);
29}
30
17static struct nft_af_info nft_af_arp __read_mostly = { 31static struct nft_af_info nft_af_arp __read_mostly = {
18 .family = NFPROTO_ARP, 32 .family = NFPROTO_ARP,
19 .nhooks = NF_ARP_NUMHOOKS, 33 .nhooks = NF_ARP_NUMHOOKS,
20 .owner = THIS_MODULE, 34 .owner = THIS_MODULE,
35 .nops = 1,
36 .hooks = {
37 [NF_ARP_IN] = nft_do_chain_arp,
38 [NF_ARP_OUT] = nft_do_chain_arp,
39 [NF_ARP_FORWARD] = nft_do_chain_arp,
40 },
21}; 41};
22 42
23static int nf_tables_arp_init_net(struct net *net) 43static int nf_tables_arp_init_net(struct net *net)
@@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_arp_net_ops = {
48 .exit = nf_tables_arp_exit_net, 68 .exit = nf_tables_arp_exit_net,
49}; 69};
50 70
51static unsigned int 71static const struct nf_chain_type filter_arp = {
52nft_do_chain_arp(const struct nf_hook_ops *ops,
53 struct sk_buff *skb,
54 const struct net_device *in,
55 const struct net_device *out,
56 int (*okfn)(struct sk_buff *))
57{
58 struct nft_pktinfo pkt;
59
60 nft_set_pktinfo(&pkt, ops, skb, in, out);
61
62 return nft_do_chain_pktinfo(&pkt, ops);
63}
64
65static struct nf_chain_type filter_arp = {
66 .family = NFPROTO_ARP,
67 .name = "filter", 72 .name = "filter",
68 .type = NFT_CHAIN_T_DEFAULT, 73 .type = NFT_CHAIN_T_DEFAULT,
74 .family = NFPROTO_ARP,
75 .owner = THIS_MODULE,
69 .hook_mask = (1 << NF_ARP_IN) | 76 .hook_mask = (1 << NF_ARP_IN) |
70 (1 << NF_ARP_OUT) | 77 (1 << NF_ARP_OUT) |
71 (1 << NF_ARP_FORWARD), 78 (1 << NF_ARP_FORWARD),
72 .fn = {
73 [NF_ARP_IN] = nft_do_chain_arp,
74 [NF_ARP_OUT] = nft_do_chain_arp,
75 [NF_ARP_FORWARD] = nft_do_chain_arp,
76 },
77}; 79};
78 80
79static int __init nf_tables_arp_init(void) 81static int __init nf_tables_arp_init(void)
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c
index 0f4cbfeb19bd..6820c8c40842 100644
--- a/net/ipv4/netfilter/nf_tables_ipv4.c
+++ b/net/ipv4/netfilter/nf_tables_ipv4.c
@@ -18,14 +18,25 @@
18#include <net/ip.h> 18#include <net/ip.h>
19#include <net/netfilter/nf_tables_ipv4.h> 19#include <net/netfilter/nf_tables_ipv4.h>
20 20
21static unsigned int nft_do_chain_ipv4(const struct nf_hook_ops *ops,
22 struct sk_buff *skb,
23 const struct net_device *in,
24 const struct net_device *out,
25 int (*okfn)(struct sk_buff *))
26{
27 struct nft_pktinfo pkt;
28
29 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
30
31 return nft_do_chain(&pkt, ops);
32}
33
21static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, 34static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops,
22 struct sk_buff *skb, 35 struct sk_buff *skb,
23 const struct net_device *in, 36 const struct net_device *in,
24 const struct net_device *out, 37 const struct net_device *out,
25 int (*okfn)(struct sk_buff *)) 38 int (*okfn)(struct sk_buff *))
26{ 39{
27 struct nft_pktinfo pkt;
28
29 if (unlikely(skb->len < sizeof(struct iphdr) || 40 if (unlikely(skb->len < sizeof(struct iphdr) ||
30 ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { 41 ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
31 if (net_ratelimit()) 42 if (net_ratelimit())
@@ -33,19 +44,24 @@ static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops,
33 "packet\n"); 44 "packet\n");
34 return NF_ACCEPT; 45 return NF_ACCEPT;
35 } 46 }
36 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
37 47
38 return nft_do_chain_pktinfo(&pkt, ops); 48 return nft_do_chain_ipv4(ops, skb, in, out, okfn);
39} 49}
40 50
41static struct nft_af_info nft_af_ipv4 __read_mostly = { 51struct nft_af_info nft_af_ipv4 __read_mostly = {
42 .family = NFPROTO_IPV4, 52 .family = NFPROTO_IPV4,
43 .nhooks = NF_INET_NUMHOOKS, 53 .nhooks = NF_INET_NUMHOOKS,
44 .owner = THIS_MODULE, 54 .owner = THIS_MODULE,
55 .nops = 1,
45 .hooks = { 56 .hooks = {
57 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
46 [NF_INET_LOCAL_OUT] = nft_ipv4_output, 58 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
59 [NF_INET_FORWARD] = nft_do_chain_ipv4,
60 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
61 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
47 }, 62 },
48}; 63};
64EXPORT_SYMBOL_GPL(nft_af_ipv4);
49 65
50static int nf_tables_ipv4_init_net(struct net *net) 66static int nf_tables_ipv4_init_net(struct net *net)
51{ 67{
@@ -75,42 +91,28 @@ static struct pernet_operations nf_tables_ipv4_net_ops = {
75 .exit = nf_tables_ipv4_exit_net, 91 .exit = nf_tables_ipv4_exit_net,
76}; 92};
77 93
78static unsigned int 94static const struct nf_chain_type filter_ipv4 = {
79nft_do_chain_ipv4(const struct nf_hook_ops *ops,
80 struct sk_buff *skb,
81 const struct net_device *in,
82 const struct net_device *out,
83 int (*okfn)(struct sk_buff *))
84{
85 struct nft_pktinfo pkt;
86
87 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
88
89 return nft_do_chain_pktinfo(&pkt, ops);
90}
91
92static struct nf_chain_type filter_ipv4 = {
93 .family = NFPROTO_IPV4,
94 .name = "filter", 95 .name = "filter",
95 .type = NFT_CHAIN_T_DEFAULT, 96 .type = NFT_CHAIN_T_DEFAULT,
97 .family = NFPROTO_IPV4,
98 .owner = THIS_MODULE,
96 .hook_mask = (1 << NF_INET_LOCAL_IN) | 99 .hook_mask = (1 << NF_INET_LOCAL_IN) |
97 (1 << NF_INET_LOCAL_OUT) | 100 (1 << NF_INET_LOCAL_OUT) |
98 (1 << NF_INET_FORWARD) | 101 (1 << NF_INET_FORWARD) |
99 (1 << NF_INET_PRE_ROUTING) | 102 (1 << NF_INET_PRE_ROUTING) |
100 (1 << NF_INET_POST_ROUTING), 103 (1 << NF_INET_POST_ROUTING),
101 .fn = {
102 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
103 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
104 [NF_INET_FORWARD] = nft_do_chain_ipv4,
105 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
106 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
107 },
108}; 104};
109 105
110static int __init nf_tables_ipv4_init(void) 106static int __init nf_tables_ipv4_init(void)
111{ 107{
108 int ret;
109
112 nft_register_chain_type(&filter_ipv4); 110 nft_register_chain_type(&filter_ipv4);
113 return register_pernet_subsys(&nf_tables_ipv4_net_ops); 111 ret = register_pernet_subsys(&nf_tables_ipv4_net_ops);
112 if (ret < 0)
113 nft_unregister_chain_type(&filter_ipv4);
114
115 return ret;
114} 116}
115 117
116static void __exit nf_tables_ipv4_exit(void) 118static void __exit nf_tables_ipv4_exit(void)
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index cf2c792cd971..b5b256d45e67 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -75,7 +75,7 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops,
75 75
76 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 76 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
77 77
78 ret = nft_do_chain_pktinfo(&pkt, ops); 78 ret = nft_do_chain(&pkt, ops);
79 if (ret != NF_ACCEPT) 79 if (ret != NF_ACCEPT)
80 return ret; 80 return ret;
81 if (!nf_nat_initialized(ct, maniptype)) { 81 if (!nf_nat_initialized(ct, maniptype)) {
@@ -164,21 +164,21 @@ static unsigned int nf_nat_output(const struct nf_hook_ops *ops,
164 return ret; 164 return ret;
165} 165}
166 166
167static struct nf_chain_type nft_chain_nat_ipv4 = { 167static const struct nf_chain_type nft_chain_nat_ipv4 = {
168 .family = NFPROTO_IPV4,
169 .name = "nat", 168 .name = "nat",
170 .type = NFT_CHAIN_T_NAT, 169 .type = NFT_CHAIN_T_NAT,
170 .family = NFPROTO_IPV4,
171 .owner = THIS_MODULE,
171 .hook_mask = (1 << NF_INET_PRE_ROUTING) | 172 .hook_mask = (1 << NF_INET_PRE_ROUTING) |
172 (1 << NF_INET_POST_ROUTING) | 173 (1 << NF_INET_POST_ROUTING) |
173 (1 << NF_INET_LOCAL_OUT) | 174 (1 << NF_INET_LOCAL_OUT) |
174 (1 << NF_INET_LOCAL_IN), 175 (1 << NF_INET_LOCAL_IN),
175 .fn = { 176 .hooks = {
176 [NF_INET_PRE_ROUTING] = nf_nat_prerouting, 177 [NF_INET_PRE_ROUTING] = nf_nat_prerouting,
177 [NF_INET_POST_ROUTING] = nf_nat_postrouting, 178 [NF_INET_POST_ROUTING] = nf_nat_postrouting,
178 [NF_INET_LOCAL_OUT] = nf_nat_output, 179 [NF_INET_LOCAL_OUT] = nf_nat_output,
179 [NF_INET_LOCAL_IN] = nf_nat_fn, 180 [NF_INET_LOCAL_IN] = nf_nat_fn,
180 }, 181 },
181 .me = THIS_MODULE,
182}; 182};
183 183
184static int __init nft_chain_nat_init(void) 184static int __init nft_chain_nat_init(void)
diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c
index 4e6bf9a3d7aa..125b66766c0a 100644
--- a/net/ipv4/netfilter/nft_chain_route_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c
@@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
47 daddr = iph->daddr; 47 daddr = iph->daddr;
48 tos = iph->tos; 48 tos = iph->tos;
49 49
50 ret = nft_do_chain_pktinfo(&pkt, ops); 50 ret = nft_do_chain(&pkt, ops);
51 if (ret != NF_DROP && ret != NF_QUEUE) { 51 if (ret != NF_DROP && ret != NF_QUEUE) {
52 iph = ip_hdr(skb); 52 iph = ip_hdr(skb);
53 53
@@ -61,15 +61,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
61 return ret; 61 return ret;
62} 62}
63 63
64static struct nf_chain_type nft_chain_route_ipv4 = { 64static const struct nf_chain_type nft_chain_route_ipv4 = {
65 .family = NFPROTO_IPV4,
66 .name = "route", 65 .name = "route",
67 .type = NFT_CHAIN_T_ROUTE, 66 .type = NFT_CHAIN_T_ROUTE,
67 .family = NFPROTO_IPV4,
68 .owner = THIS_MODULE,
68 .hook_mask = (1 << NF_INET_LOCAL_OUT), 69 .hook_mask = (1 << NF_INET_LOCAL_OUT),
69 .fn = { 70 .hooks = {
70 [NF_INET_LOCAL_OUT] = nf_route_table_hook, 71 [NF_INET_LOCAL_OUT] = nf_route_table_hook,
71 }, 72 },
72 .me = THIS_MODULE,
73}; 73};
74 74
75static int __init nft_chain_route_init(void) 75static int __init nft_chain_route_init(void)
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c
index d77db8a13505..0d812b31277d 100644
--- a/net/ipv6/netfilter/nf_tables_ipv6.c
+++ b/net/ipv6/netfilter/nf_tables_ipv6.c
@@ -16,34 +16,51 @@
16#include <net/netfilter/nf_tables.h> 16#include <net/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_ipv6.h> 17#include <net/netfilter/nf_tables_ipv6.h>
18 18
19static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops,
20 struct sk_buff *skb,
21 const struct net_device *in,
22 const struct net_device *out,
23 int (*okfn)(struct sk_buff *))
24{
25 struct nft_pktinfo pkt;
26
27 /* malformed packet, drop it */
28 if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
29 return NF_DROP;
30
31 return nft_do_chain(&pkt, ops);
32}
33
19static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, 34static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops,
20 struct sk_buff *skb, 35 struct sk_buff *skb,
21 const struct net_device *in, 36 const struct net_device *in,
22 const struct net_device *out, 37 const struct net_device *out,
23 int (*okfn)(struct sk_buff *)) 38 int (*okfn)(struct sk_buff *))
24{ 39{
25 struct nft_pktinfo pkt;
26
27 if (unlikely(skb->len < sizeof(struct ipv6hdr))) { 40 if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
28 if (net_ratelimit()) 41 if (net_ratelimit())
29 pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " 42 pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
30 "packet\n"); 43 "packet\n");
31 return NF_ACCEPT; 44 return NF_ACCEPT;
32 } 45 }
33 if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
34 return NF_DROP;
35 46
36 return nft_do_chain_pktinfo(&pkt, ops); 47 return nft_do_chain_ipv6(ops, skb, in, out, okfn);
37} 48}
38 49
39static struct nft_af_info nft_af_ipv6 __read_mostly = { 50struct nft_af_info nft_af_ipv6 __read_mostly = {
40 .family = NFPROTO_IPV6, 51 .family = NFPROTO_IPV6,
41 .nhooks = NF_INET_NUMHOOKS, 52 .nhooks = NF_INET_NUMHOOKS,
42 .owner = THIS_MODULE, 53 .owner = THIS_MODULE,
54 .nops = 1,
43 .hooks = { 55 .hooks = {
56 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
44 [NF_INET_LOCAL_OUT] = nft_ipv6_output, 57 [NF_INET_LOCAL_OUT] = nft_ipv6_output,
58 [NF_INET_FORWARD] = nft_do_chain_ipv6,
59 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
60 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
45 }, 61 },
46}; 62};
63EXPORT_SYMBOL_GPL(nft_af_ipv6);
47 64
48static int nf_tables_ipv6_init_net(struct net *net) 65static int nf_tables_ipv6_init_net(struct net *net)
49{ 66{
@@ -73,44 +90,28 @@ static struct pernet_operations nf_tables_ipv6_net_ops = {
73 .exit = nf_tables_ipv6_exit_net, 90 .exit = nf_tables_ipv6_exit_net,
74}; 91};
75 92
76static unsigned int 93static const struct nf_chain_type filter_ipv6 = {
77nft_do_chain_ipv6(const struct nf_hook_ops *ops,
78 struct sk_buff *skb,
79 const struct net_device *in,
80 const struct net_device *out,
81 int (*okfn)(struct sk_buff *))
82{
83 struct nft_pktinfo pkt;
84
85 /* malformed packet, drop it */
86 if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
87 return NF_DROP;
88
89 return nft_do_chain_pktinfo(&pkt, ops);
90}
91
92static struct nf_chain_type filter_ipv6 = {
93 .family = NFPROTO_IPV6,
94 .name = "filter", 94 .name = "filter",
95 .type = NFT_CHAIN_T_DEFAULT, 95 .type = NFT_CHAIN_T_DEFAULT,
96 .family = NFPROTO_IPV6,
97 .owner = THIS_MODULE,
96 .hook_mask = (1 << NF_INET_LOCAL_IN) | 98 .hook_mask = (1 << NF_INET_LOCAL_IN) |
97 (1 << NF_INET_LOCAL_OUT) | 99 (1 << NF_INET_LOCAL_OUT) |
98 (1 << NF_INET_FORWARD) | 100 (1 << NF_INET_FORWARD) |
99 (1 << NF_INET_PRE_ROUTING) | 101 (1 << NF_INET_PRE_ROUTING) |
100 (1 << NF_INET_POST_ROUTING), 102 (1 << NF_INET_POST_ROUTING),
101 .fn = {
102 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
103 [NF_INET_LOCAL_OUT] = nft_ipv6_output,
104 [NF_INET_FORWARD] = nft_do_chain_ipv6,
105 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
106 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
107 },
108}; 103};
109 104
110static int __init nf_tables_ipv6_init(void) 105static int __init nf_tables_ipv6_init(void)
111{ 106{
107 int ret;
108
112 nft_register_chain_type(&filter_ipv6); 109 nft_register_chain_type(&filter_ipv6);
113 return register_pernet_subsys(&nf_tables_ipv6_net_ops); 110 ret = register_pernet_subsys(&nf_tables_ipv6_net_ops);
111 if (ret < 0)
112 nft_unregister_chain_type(&filter_ipv6);
113
114 return ret;
114} 115}
115 116
116static void __exit nf_tables_ipv6_exit(void) 117static void __exit nf_tables_ipv6_exit(void)
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
index e86dcd70dc76..9c3297a768fd 100644
--- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c
+++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
@@ -79,7 +79,7 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
79 79
80 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); 80 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
81 81
82 ret = nft_do_chain_pktinfo(&pkt, ops); 82 ret = nft_do_chain(&pkt, ops);
83 if (ret != NF_ACCEPT) 83 if (ret != NF_ACCEPT)
84 return ret; 84 return ret;
85 if (!nf_nat_initialized(ct, maniptype)) { 85 if (!nf_nat_initialized(ct, maniptype)) {
@@ -170,21 +170,21 @@ static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops,
170 return ret; 170 return ret;
171} 171}
172 172
173static struct nf_chain_type nft_chain_nat_ipv6 = { 173static const struct nf_chain_type nft_chain_nat_ipv6 = {
174 .family = NFPROTO_IPV6,
175 .name = "nat", 174 .name = "nat",
176 .type = NFT_CHAIN_T_NAT, 175 .type = NFT_CHAIN_T_NAT,
176 .family = NFPROTO_IPV6,
177 .owner = THIS_MODULE,
177 .hook_mask = (1 << NF_INET_PRE_ROUTING) | 178 .hook_mask = (1 << NF_INET_PRE_ROUTING) |
178 (1 << NF_INET_POST_ROUTING) | 179 (1 << NF_INET_POST_ROUTING) |
179 (1 << NF_INET_LOCAL_OUT) | 180 (1 << NF_INET_LOCAL_OUT) |
180 (1 << NF_INET_LOCAL_IN), 181 (1 << NF_INET_LOCAL_IN),
181 .fn = { 182 .hooks = {
182 [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, 183 [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting,
183 [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, 184 [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting,
184 [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, 185 [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output,
185 [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, 186 [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn,
186 }, 187 },
187 .me = THIS_MODULE,
188}; 188};
189 189
190static int __init nft_chain_nat_ipv6_init(void) 190static int __init nft_chain_nat_ipv6_init(void)
diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c
index 3fe40f0456ad..42031299585e 100644
--- a/net/ipv6/netfilter/nft_chain_route_ipv6.c
+++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c
@@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
47 /* flowlabel and prio (includes version, which shouldn't change either */ 47 /* flowlabel and prio (includes version, which shouldn't change either */
48 flowlabel = *((u32 *)ipv6_hdr(skb)); 48 flowlabel = *((u32 *)ipv6_hdr(skb));
49 49
50 ret = nft_do_chain_pktinfo(&pkt, ops); 50 ret = nft_do_chain(&pkt, ops);
51 if (ret != NF_DROP && ret != NF_QUEUE && 51 if (ret != NF_DROP && ret != NF_QUEUE &&
52 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || 52 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
53 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || 53 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
@@ -59,15 +59,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
59 return ret; 59 return ret;
60} 60}
61 61
62static struct nf_chain_type nft_chain_route_ipv6 = { 62static const struct nf_chain_type nft_chain_route_ipv6 = {
63 .family = NFPROTO_IPV6,
64 .name = "route", 63 .name = "route",
65 .type = NFT_CHAIN_T_ROUTE, 64 .type = NFT_CHAIN_T_ROUTE,
65 .family = NFPROTO_IPV6,
66 .owner = THIS_MODULE,
66 .hook_mask = (1 << NF_INET_LOCAL_OUT), 67 .hook_mask = (1 << NF_INET_LOCAL_OUT),
67 .fn = { 68 .hooks = {
68 [NF_INET_LOCAL_OUT] = nf_route_table_hook, 69 [NF_INET_LOCAL_OUT] = nf_route_table_hook,
69 }, 70 },
70 .me = THIS_MODULE,
71}; 71};
72 72
73static int __init nft_chain_route_init(void) 73static int __init nft_chain_route_init(void)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c3b3b26c4c4e..37d2092705a7 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -428,6 +428,14 @@ config NF_TABLES
428 428
429 To compile it as a module, choose M here. 429 To compile it as a module, choose M here.
430 430
431config NF_TABLES_INET
432 depends on NF_TABLES
433 select NF_TABLES_IPV4
434 select NF_TABLES_IPV6
435 tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support"
436 help
437 This option enables support for a mixed IPv4/IPv6 "inet" table.
438
431config NFT_EXTHDR 439config NFT_EXTHDR
432 depends on NF_TABLES 440 depends on NF_TABLES
433 tristate "Netfilter nf_tables IPv6 exthdr module" 441 tristate "Netfilter nf_tables IPv6 exthdr module"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 78b4e1c9c595..74c066109334 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -70,6 +70,7 @@ nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o
70nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o 70nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
71 71
72obj-$(CONFIG_NF_TABLES) += nf_tables.o 72obj-$(CONFIG_NF_TABLES) += nf_tables.o
73obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o
73obj-$(CONFIG_NFT_COMPAT) += nft_compat.o 74obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
74obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o 75obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
75obj-$(CONFIG_NFT_META) += nft_meta.o 76obj-$(CONFIG_NFT_META) += nft_meta.o
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 1fcef1ec1dc1..36add31e08e7 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -124,37 +124,43 @@ static inline u64 nf_tables_alloc_handle(struct nft_table *table)
124 return ++table->hgenerator; 124 return ++table->hgenerator;
125} 125}
126 126
127static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX]; 127static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
128 128
129static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) 129static const struct nf_chain_type *
130__nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
130{ 131{
131 int i; 132 int i;
132 133
133 for (i=0; i<NFT_CHAIN_T_MAX; i++) { 134 for (i = 0; i < NFT_CHAIN_T_MAX; i++) {
134 if (chain_type[family][i] != NULL && 135 if (chain_type[family][i] != NULL &&
135 !nla_strcmp(nla, chain_type[family][i]->name)) 136 !nla_strcmp(nla, chain_type[family][i]->name))
136 return i; 137 return chain_type[family][i];
137 } 138 }
138 return -1; 139 return NULL;
139} 140}
140 141
141static int nf_tables_chain_type_lookup(const struct nft_af_info *afi, 142static const struct nf_chain_type *
142 const struct nlattr *nla, 143nf_tables_chain_type_lookup(const struct nft_af_info *afi,
143 bool autoload) 144 const struct nlattr *nla,
145 bool autoload)
144{ 146{
145 int type; 147 const struct nf_chain_type *type;
146 148
147 type = __nf_tables_chain_type_lookup(afi->family, nla); 149 type = __nf_tables_chain_type_lookup(afi->family, nla);
150 if (type != NULL)
151 return type;
148#ifdef CONFIG_MODULES 152#ifdef CONFIG_MODULES
149 if (type < 0 && autoload) { 153 if (autoload) {
150 nfnl_unlock(NFNL_SUBSYS_NFTABLES); 154 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
151 request_module("nft-chain-%u-%*.s", afi->family, 155 request_module("nft-chain-%u-%*.s", afi->family,
152 nla_len(nla)-1, (const char *)nla_data(nla)); 156 nla_len(nla)-1, (const char *)nla_data(nla));
153 nfnl_lock(NFNL_SUBSYS_NFTABLES); 157 nfnl_lock(NFNL_SUBSYS_NFTABLES);
154 type = __nf_tables_chain_type_lookup(afi->family, nla); 158 type = __nf_tables_chain_type_lookup(afi->family, nla);
159 if (type != NULL)
160 return ERR_PTR(-EAGAIN);
155 } 161 }
156#endif 162#endif
157 return type; 163 return ERR_PTR(-ENOENT);
158} 164}
159 165
160static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { 166static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
@@ -307,7 +313,8 @@ err:
307 return err; 313 return err;
308} 314}
309 315
310static int nf_tables_table_enable(struct nft_table *table) 316static int nf_tables_table_enable(const struct nft_af_info *afi,
317 struct nft_table *table)
311{ 318{
312 struct nft_chain *chain; 319 struct nft_chain *chain;
313 int err, i = 0; 320 int err, i = 0;
@@ -316,7 +323,7 @@ static int nf_tables_table_enable(struct nft_table *table)
316 if (!(chain->flags & NFT_BASE_CHAIN)) 323 if (!(chain->flags & NFT_BASE_CHAIN))
317 continue; 324 continue;
318 325
319 err = nf_register_hook(&nft_base_chain(chain)->ops); 326 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
320 if (err < 0) 327 if (err < 0)
321 goto err; 328 goto err;
322 329
@@ -331,18 +338,20 @@ err:
331 if (i-- <= 0) 338 if (i-- <= 0)
332 break; 339 break;
333 340
334 nf_unregister_hook(&nft_base_chain(chain)->ops); 341 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
335 } 342 }
336 return err; 343 return err;
337} 344}
338 345
339static int nf_tables_table_disable(struct nft_table *table) 346static int nf_tables_table_disable(const struct nft_af_info *afi,
347 struct nft_table *table)
340{ 348{
341 struct nft_chain *chain; 349 struct nft_chain *chain;
342 350
343 list_for_each_entry(chain, &table->chains, list) { 351 list_for_each_entry(chain, &table->chains, list) {
344 if (chain->flags & NFT_BASE_CHAIN) 352 if (chain->flags & NFT_BASE_CHAIN)
345 nf_unregister_hook(&nft_base_chain(chain)->ops); 353 nf_unregister_hooks(nft_base_chain(chain)->ops,
354 afi->nops);
346 } 355 }
347 356
348 return 0; 357 return 0;
@@ -357,7 +366,7 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
357 int family = nfmsg->nfgen_family, ret = 0; 366 int family = nfmsg->nfgen_family, ret = 0;
358 367
359 if (nla[NFTA_TABLE_FLAGS]) { 368 if (nla[NFTA_TABLE_FLAGS]) {
360 __be32 flags; 369 u32 flags;
361 370
362 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); 371 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
363 if (flags & ~NFT_TABLE_F_DORMANT) 372 if (flags & ~NFT_TABLE_F_DORMANT)
@@ -365,12 +374,12 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
365 374
366 if ((flags & NFT_TABLE_F_DORMANT) && 375 if ((flags & NFT_TABLE_F_DORMANT) &&
367 !(table->flags & NFT_TABLE_F_DORMANT)) { 376 !(table->flags & NFT_TABLE_F_DORMANT)) {
368 ret = nf_tables_table_disable(table); 377 ret = nf_tables_table_disable(afi, table);
369 if (ret >= 0) 378 if (ret >= 0)
370 table->flags |= NFT_TABLE_F_DORMANT; 379 table->flags |= NFT_TABLE_F_DORMANT;
371 } else if (!(flags & NFT_TABLE_F_DORMANT) && 380 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
372 table->flags & NFT_TABLE_F_DORMANT) { 381 table->flags & NFT_TABLE_F_DORMANT) {
373 ret = nf_tables_table_enable(table); 382 ret = nf_tables_table_enable(afi, table);
374 if (ret >= 0) 383 if (ret >= 0)
375 table->flags &= ~NFT_TABLE_F_DORMANT; 384 table->flags &= ~NFT_TABLE_F_DORMANT;
376 } 385 }
@@ -393,6 +402,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
393 struct nft_table *table; 402 struct nft_table *table;
394 struct net *net = sock_net(skb->sk); 403 struct net *net = sock_net(skb->sk);
395 int family = nfmsg->nfgen_family; 404 int family = nfmsg->nfgen_family;
405 u32 flags = 0;
396 406
397 afi = nf_tables_afinfo_lookup(net, family, true); 407 afi = nf_tables_afinfo_lookup(net, family, true);
398 if (IS_ERR(afi)) 408 if (IS_ERR(afi))
@@ -414,25 +424,25 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
414 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table); 424 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
415 } 425 }
416 426
427 if (nla[NFTA_TABLE_FLAGS]) {
428 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
429 if (flags & ~NFT_TABLE_F_DORMANT)
430 return -EINVAL;
431 }
432
433 if (!try_module_get(afi->owner))
434 return -EAFNOSUPPORT;
435
417 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL); 436 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
418 if (table == NULL) 437 if (table == NULL) {
438 module_put(afi->owner);
419 return -ENOMEM; 439 return -ENOMEM;
440 }
420 441
421 nla_strlcpy(table->name, name, nla_len(name)); 442 nla_strlcpy(table->name, name, nla_len(name));
422 INIT_LIST_HEAD(&table->chains); 443 INIT_LIST_HEAD(&table->chains);
423 INIT_LIST_HEAD(&table->sets); 444 INIT_LIST_HEAD(&table->sets);
424 445 table->flags = flags;
425 if (nla[NFTA_TABLE_FLAGS]) {
426 __be32 flags;
427
428 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
429 if (flags & ~NFT_TABLE_F_DORMANT) {
430 kfree(table);
431 return -EINVAL;
432 }
433
434 table->flags |= flags;
435 }
436 446
437 list_add_tail(&table->list, &afi->tables); 447 list_add_tail(&table->list, &afi->tables);
438 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); 448 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
@@ -457,16 +467,17 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
457 if (IS_ERR(table)) 467 if (IS_ERR(table))
458 return PTR_ERR(table); 468 return PTR_ERR(table);
459 469
460 if (table->use) 470 if (!list_empty(&table->chains) || !list_empty(&table->sets))
461 return -EBUSY; 471 return -EBUSY;
462 472
463 list_del(&table->list); 473 list_del(&table->list);
464 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family); 474 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
465 kfree(table); 475 kfree(table);
476 module_put(afi->owner);
466 return 0; 477 return 0;
467} 478}
468 479
469int nft_register_chain_type(struct nf_chain_type *ctype) 480int nft_register_chain_type(const struct nf_chain_type *ctype)
470{ 481{
471 int err = 0; 482 int err = 0;
472 483
@@ -475,10 +486,6 @@ int nft_register_chain_type(struct nf_chain_type *ctype)
475 err = -EBUSY; 486 err = -EBUSY;
476 goto out; 487 goto out;
477 } 488 }
478
479 if (!try_module_get(ctype->me))
480 goto out;
481
482 chain_type[ctype->family][ctype->type] = ctype; 489 chain_type[ctype->family][ctype->type] = ctype;
483out: 490out:
484 nfnl_unlock(NFNL_SUBSYS_NFTABLES); 491 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
@@ -486,11 +493,10 @@ out:
486} 493}
487EXPORT_SYMBOL_GPL(nft_register_chain_type); 494EXPORT_SYMBOL_GPL(nft_register_chain_type);
488 495
489void nft_unregister_chain_type(struct nf_chain_type *ctype) 496void nft_unregister_chain_type(const struct nf_chain_type *ctype)
490{ 497{
491 nfnl_lock(NFNL_SUBSYS_NFTABLES); 498 nfnl_lock(NFNL_SUBSYS_NFTABLES);
492 chain_type[ctype->family][ctype->type] = NULL; 499 chain_type[ctype->family][ctype->type] = NULL;
493 module_put(ctype->me);
494 nfnl_unlock(NFNL_SUBSYS_NFTABLES); 500 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
495} 501}
496EXPORT_SYMBOL_GPL(nft_unregister_chain_type); 502EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
@@ -598,7 +604,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
598 604
599 if (chain->flags & NFT_BASE_CHAIN) { 605 if (chain->flags & NFT_BASE_CHAIN) {
600 const struct nft_base_chain *basechain = nft_base_chain(chain); 606 const struct nft_base_chain *basechain = nft_base_chain(chain);
601 const struct nf_hook_ops *ops = &basechain->ops; 607 const struct nf_hook_ops *ops = &basechain->ops[0];
602 struct nlattr *nest; 608 struct nlattr *nest;
603 609
604 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); 610 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
@@ -614,9 +620,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
614 htonl(basechain->policy))) 620 htonl(basechain->policy)))
615 goto nla_put_failure; 621 goto nla_put_failure;
616 622
617 if (nla_put_string(skb, NFTA_CHAIN_TYPE, 623 if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
618 chain_type[ops->pf][nft_base_chain(chain)->type]->name)) 624 goto nla_put_failure;
619 goto nla_put_failure;
620 625
621 if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) 626 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
622 goto nla_put_failure; 627 goto nla_put_failure;
@@ -757,22 +762,6 @@ err:
757 return err; 762 return err;
758} 763}
759 764
760static int
761nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
762{
763 switch (ntohl(nla_get_be32(attr))) {
764 case NF_DROP:
765 chain->policy = NF_DROP;
766 break;
767 case NF_ACCEPT:
768 chain->policy = NF_ACCEPT;
769 break;
770 default:
771 return -EINVAL;
772 }
773 return 0;
774}
775
776static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { 765static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
777 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, 766 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
778 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, 767 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
@@ -831,7 +820,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
831 struct nlattr *ha[NFTA_HOOK_MAX + 1]; 820 struct nlattr *ha[NFTA_HOOK_MAX + 1];
832 struct net *net = sock_net(skb->sk); 821 struct net *net = sock_net(skb->sk);
833 int family = nfmsg->nfgen_family; 822 int family = nfmsg->nfgen_family;
823 u8 policy = NF_ACCEPT;
834 u64 handle = 0; 824 u64 handle = 0;
825 unsigned int i;
835 int err; 826 int err;
836 bool create; 827 bool create;
837 828
@@ -845,9 +836,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
845 if (IS_ERR(table)) 836 if (IS_ERR(table))
846 return PTR_ERR(table); 837 return PTR_ERR(table);
847 838
848 if (table->use == UINT_MAX)
849 return -EOVERFLOW;
850
851 chain = NULL; 839 chain = NULL;
852 name = nla[NFTA_CHAIN_NAME]; 840 name = nla[NFTA_CHAIN_NAME];
853 841
@@ -865,6 +853,22 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
865 } 853 }
866 } 854 }
867 855
856 if (nla[NFTA_CHAIN_POLICY]) {
857 if ((chain != NULL &&
858 !(chain->flags & NFT_BASE_CHAIN)) ||
859 nla[NFTA_CHAIN_HOOK] == NULL)
860 return -EOPNOTSUPP;
861
862 policy = nla_get_be32(nla[NFTA_CHAIN_POLICY]);
863 switch (policy) {
864 case NF_DROP:
865 case NF_ACCEPT:
866 break;
867 default:
868 return -EINVAL;
869 }
870 }
871
868 if (chain != NULL) { 872 if (chain != NULL) {
869 if (nlh->nlmsg_flags & NLM_F_EXCL) 873 if (nlh->nlmsg_flags & NLM_F_EXCL)
870 return -EEXIST; 874 return -EEXIST;
@@ -875,16 +879,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
875 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) 879 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
876 return -EEXIST; 880 return -EEXIST;
877 881
878 if (nla[NFTA_CHAIN_POLICY]) {
879 if (!(chain->flags & NFT_BASE_CHAIN))
880 return -EOPNOTSUPP;
881
882 err = nf_tables_chain_policy(nft_base_chain(chain),
883 nla[NFTA_CHAIN_POLICY]);
884 if (err < 0)
885 return err;
886 }
887
888 if (nla[NFTA_CHAIN_COUNTERS]) { 882 if (nla[NFTA_CHAIN_COUNTERS]) {
889 if (!(chain->flags & NFT_BASE_CHAIN)) 883 if (!(chain->flags & NFT_BASE_CHAIN))
890 return -EOPNOTSUPP; 884 return -EOPNOTSUPP;
@@ -895,24 +889,31 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
895 return err; 889 return err;
896 } 890 }
897 891
892 if (nla[NFTA_CHAIN_POLICY])
893 nft_base_chain(chain)->policy = policy;
894
898 if (nla[NFTA_CHAIN_HANDLE] && name) 895 if (nla[NFTA_CHAIN_HANDLE] && name)
899 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); 896 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
900 897
901 goto notify; 898 goto notify;
902 } 899 }
903 900
901 if (table->use == UINT_MAX)
902 return -EOVERFLOW;
903
904 if (nla[NFTA_CHAIN_HOOK]) { 904 if (nla[NFTA_CHAIN_HOOK]) {
905 const struct nf_chain_type *type;
905 struct nf_hook_ops *ops; 906 struct nf_hook_ops *ops;
906 nf_hookfn *hookfn; 907 nf_hookfn *hookfn;
907 u32 hooknum; 908 u32 hooknum, priority;
908 int type = NFT_CHAIN_T_DEFAULT;
909 909
910 type = chain_type[family][NFT_CHAIN_T_DEFAULT];
910 if (nla[NFTA_CHAIN_TYPE]) { 911 if (nla[NFTA_CHAIN_TYPE]) {
911 type = nf_tables_chain_type_lookup(afi, 912 type = nf_tables_chain_type_lookup(afi,
912 nla[NFTA_CHAIN_TYPE], 913 nla[NFTA_CHAIN_TYPE],
913 create); 914 create);
914 if (type < 0) 915 if (IS_ERR(type))
915 return -ENOENT; 916 return PTR_ERR(type);
916 } 917 }
917 918
918 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK], 919 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
@@ -926,46 +927,23 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
926 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); 927 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
927 if (hooknum >= afi->nhooks) 928 if (hooknum >= afi->nhooks)
928 return -EINVAL; 929 return -EINVAL;
930 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
929 931
930 hookfn = chain_type[family][type]->fn[hooknum]; 932 if (!(type->hook_mask & (1 << hooknum)))
931 if (hookfn == NULL)
932 return -EOPNOTSUPP; 933 return -EOPNOTSUPP;
934 if (!try_module_get(type->owner))
935 return -ENOENT;
936 hookfn = type->hooks[hooknum];
933 937
934 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); 938 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
935 if (basechain == NULL) 939 if (basechain == NULL)
936 return -ENOMEM; 940 return -ENOMEM;
937 941
938 basechain->type = type;
939 chain = &basechain->chain;
940
941 ops = &basechain->ops;
942 ops->pf = family;
943 ops->owner = afi->owner;
944 ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
945 ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
946 ops->priv = chain;
947 ops->hook = hookfn;
948 if (afi->hooks[ops->hooknum])
949 ops->hook = afi->hooks[ops->hooknum];
950
951 chain->flags |= NFT_BASE_CHAIN;
952
953 if (nla[NFTA_CHAIN_POLICY]) {
954 err = nf_tables_chain_policy(basechain,
955 nla[NFTA_CHAIN_POLICY]);
956 if (err < 0) {
957 free_percpu(basechain->stats);
958 kfree(basechain);
959 return err;
960 }
961 } else
962 basechain->policy = NF_ACCEPT;
963
964 if (nla[NFTA_CHAIN_COUNTERS]) { 942 if (nla[NFTA_CHAIN_COUNTERS]) {
965 err = nf_tables_counters(basechain, 943 err = nf_tables_counters(basechain,
966 nla[NFTA_CHAIN_COUNTERS]); 944 nla[NFTA_CHAIN_COUNTERS]);
967 if (err < 0) { 945 if (err < 0) {
968 free_percpu(basechain->stats); 946 module_put(type->owner);
969 kfree(basechain); 947 kfree(basechain);
970 return err; 948 return err;
971 } 949 }
@@ -973,12 +951,33 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
973 struct nft_stats __percpu *newstats; 951 struct nft_stats __percpu *newstats;
974 952
975 newstats = alloc_percpu(struct nft_stats); 953 newstats = alloc_percpu(struct nft_stats);
976 if (newstats == NULL) 954 if (newstats == NULL) {
955 module_put(type->owner);
956 kfree(basechain);
977 return -ENOMEM; 957 return -ENOMEM;
958 }
959 rcu_assign_pointer(basechain->stats, newstats);
960 }
978 961
979 rcu_assign_pointer(nft_base_chain(chain)->stats, 962 basechain->type = type;
980 newstats); 963 chain = &basechain->chain;
964
965 for (i = 0; i < afi->nops; i++) {
966 ops = &basechain->ops[i];
967 ops->pf = family;
968 ops->owner = afi->owner;
969 ops->hooknum = hooknum;
970 ops->priority = priority;
971 ops->priv = chain;
972 ops->hook = afi->hooks[ops->hooknum];
973 if (hookfn)
974 ops->hook = hookfn;
975 if (afi->hook_ops_init)
976 afi->hook_ops_init(ops, i);
981 } 977 }
978
979 chain->flags |= NFT_BASE_CHAIN;
980 basechain->policy = policy;
982 } else { 981 } else {
983 chain = kzalloc(sizeof(*chain), GFP_KERNEL); 982 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
984 if (chain == NULL) 983 if (chain == NULL)
@@ -993,8 +992,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
993 992
994 if (!(table->flags & NFT_TABLE_F_DORMANT) && 993 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
995 chain->flags & NFT_BASE_CHAIN) { 994 chain->flags & NFT_BASE_CHAIN) {
996 err = nf_register_hook(&nft_base_chain(chain)->ops); 995 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
997 if (err < 0) { 996 if (err < 0) {
997 module_put(basechain->type->owner);
998 free_percpu(basechain->stats); 998 free_percpu(basechain->stats);
999 kfree(basechain); 999 kfree(basechain);
1000 return err; 1000 return err;
@@ -1015,6 +1015,7 @@ static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
1015 BUG_ON(chain->use > 0); 1015 BUG_ON(chain->use > 0);
1016 1016
1017 if (chain->flags & NFT_BASE_CHAIN) { 1017 if (chain->flags & NFT_BASE_CHAIN) {
1018 module_put(nft_base_chain(chain)->type->owner);
1018 free_percpu(nft_base_chain(chain)->stats); 1019 free_percpu(nft_base_chain(chain)->stats);
1019 kfree(nft_base_chain(chain)); 1020 kfree(nft_base_chain(chain));
1020 } else 1021 } else
@@ -1052,7 +1053,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1052 1053
1053 if (!(table->flags & NFT_TABLE_F_DORMANT) && 1054 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1054 chain->flags & NFT_BASE_CHAIN) 1055 chain->flags & NFT_BASE_CHAIN)
1055 nf_unregister_hook(&nft_base_chain(chain)->ops); 1056 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
1056 1057
1057 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, 1058 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1058 family); 1059 family);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index e8fcc343c2b9..0d879fcb8763 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -109,14 +109,14 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
109{ 109{
110 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); 110 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
111 111
112 nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in, 112 nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
113 pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", 113 pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
114 chain->table->name, chain->name, comments[type], 114 chain->table->name, chain->name, comments[type],
115 rulenum); 115 rulenum);
116} 116}
117 117
118unsigned int 118unsigned int
119nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) 119nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
120{ 120{
121 const struct nft_chain *chain = ops->priv; 121 const struct nft_chain *chain = ops->priv;
122 const struct nft_rule *rule; 122 const struct nft_rule *rule;
@@ -216,7 +216,7 @@ next_rule:
216 216
217 return nft_base_chain(chain)->policy; 217 return nft_base_chain(chain)->policy;
218} 218}
219EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo); 219EXPORT_SYMBOL_GPL(nft_do_chain);
220 220
221int __init nf_tables_core_module_init(void) 221int __init nf_tables_core_module_init(void)
222{ 222{
diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c
new file mode 100644
index 000000000000..9dd2d216cfc1
--- /dev/null
+++ b/net/netfilter/nf_tables_inet.c
@@ -0,0 +1,104 @@
1/*
2 * Copyright (c) 2012-2014 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/ip.h>
12#include <linux/netfilter_ipv4.h>
13#include <linux/netfilter_ipv6.h>
14#include <net/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables_ipv4.h>
16#include <net/netfilter/nf_tables_ipv6.h>
17#include <net/ip.h>
18
19static void nft_inet_hook_ops_init(struct nf_hook_ops *ops, unsigned int n)
20{
21 struct nft_af_info *afi;
22
23 if (n == 1)
24 afi = &nft_af_ipv4;
25 else
26 afi = &nft_af_ipv6;
27
28 ops->pf = afi->family;
29 if (afi->hooks[ops->hooknum])
30 ops->hook = afi->hooks[ops->hooknum];
31}
32
33static struct nft_af_info nft_af_inet __read_mostly = {
34 .family = NFPROTO_INET,
35 .nhooks = NF_INET_NUMHOOKS,
36 .owner = THIS_MODULE,
37 .nops = 2,
38 .hook_ops_init = nft_inet_hook_ops_init,
39};
40
41static int __net_init nf_tables_inet_init_net(struct net *net)
42{
43 net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
44 if (net->nft.inet == NULL)
45 return -ENOMEM;
46 memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet));
47
48 if (nft_register_afinfo(net, net->nft.inet) < 0)
49 goto err;
50
51 return 0;
52
53err:
54 kfree(net->nft.inet);
55 return -ENOMEM;
56}
57
58static void __net_exit nf_tables_inet_exit_net(struct net *net)
59{
60 nft_unregister_afinfo(net->nft.inet);
61 kfree(net->nft.inet);
62}
63
64static struct pernet_operations nf_tables_inet_net_ops = {
65 .init = nf_tables_inet_init_net,
66 .exit = nf_tables_inet_exit_net,
67};
68
69static const struct nf_chain_type filter_inet = {
70 .name = "filter",
71 .type = NFT_CHAIN_T_DEFAULT,
72 .family = NFPROTO_INET,
73 .owner = THIS_MODULE,
74 .hook_mask = (1 << NF_INET_LOCAL_IN) |
75 (1 << NF_INET_LOCAL_OUT) |
76 (1 << NF_INET_FORWARD) |
77 (1 << NF_INET_PRE_ROUTING) |
78 (1 << NF_INET_POST_ROUTING),
79};
80
81static int __init nf_tables_inet_init(void)
82{
83 int ret;
84
85 nft_register_chain_type(&filter_inet);
86 ret = register_pernet_subsys(&nf_tables_inet_net_ops);
87 if (ret < 0)
88 nft_unregister_chain_type(&filter_inet);
89
90 return ret;
91}
92
93static void __exit nf_tables_inet_exit(void)
94{
95 unregister_pernet_subsys(&nf_tables_inet_net_ops);
96 nft_unregister_chain_type(&filter_inet);
97}
98
99module_init(nf_tables_inet_init);
100module_exit(nf_tables_inet_exit);
101
102MODULE_LICENSE("GPL");
103MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
104MODULE_ALIAS_NFT_FAMILY(1);
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
index da0c1f4ada12..82cb8236f8a1 100644
--- a/net/netfilter/nft_compat.c
+++ b/net/netfilter/nft_compat.c
@@ -92,7 +92,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
92 if (ctx->chain->flags & NFT_BASE_CHAIN) { 92 if (ctx->chain->flags & NFT_BASE_CHAIN) {
93 const struct nft_base_chain *basechain = 93 const struct nft_base_chain *basechain =
94 nft_base_chain(ctx->chain); 94 nft_base_chain(ctx->chain);
95 const struct nf_hook_ops *ops = &basechain->ops; 95 const struct nf_hook_ops *ops = &basechain->ops[0];
96 96
97 par->hook_mask = 1 << ops->hooknum; 97 par->hook_mask = 1 << ops->hooknum;
98 } 98 }
@@ -253,7 +253,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
253 if (ctx->chain->flags & NFT_BASE_CHAIN) { 253 if (ctx->chain->flags & NFT_BASE_CHAIN) {
254 const struct nft_base_chain *basechain = 254 const struct nft_base_chain *basechain =
255 nft_base_chain(ctx->chain); 255 nft_base_chain(ctx->chain);
256 const struct nf_hook_ops *ops = &basechain->ops; 256 const struct nf_hook_ops *ops = &basechain->ops[0];
257 257
258 hook_mask = 1 << ops->hooknum; 258 hook_mask = 1 << ops->hooknum;
259 if (hook_mask & target->hooks) 259 if (hook_mask & target->hooks)
@@ -323,7 +323,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
323 if (ctx->chain->flags & NFT_BASE_CHAIN) { 323 if (ctx->chain->flags & NFT_BASE_CHAIN) {
324 const struct nft_base_chain *basechain = 324 const struct nft_base_chain *basechain =
325 nft_base_chain(ctx->chain); 325 nft_base_chain(ctx->chain);
326 const struct nf_hook_ops *ops = &basechain->ops; 326 const struct nf_hook_ops *ops = &basechain->ops[0];
327 327
328 par->hook_mask = 1 << ops->hooknum; 328 par->hook_mask = 1 << ops->hooknum;
329 } 329 }
@@ -449,7 +449,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
449 if (ctx->chain->flags & NFT_BASE_CHAIN) { 449 if (ctx->chain->flags & NFT_BASE_CHAIN) {
450 const struct nft_base_chain *basechain = 450 const struct nft_base_chain *basechain =
451 nft_base_chain(ctx->chain); 451 nft_base_chain(ctx->chain);
452 const struct nf_hook_ops *ops = &basechain->ops; 452 const struct nf_hook_ops *ops = &basechain->ops[0];
453 453
454 hook_mask = 1 << ops->hooknum; 454 hook_mask = 1 << ops->hooknum;
455 if (hook_mask & match->hooks) 455 if (hook_mask & match->hooks)
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index 955f4e6e7089..c7c12858e113 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -18,17 +18,21 @@
18#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_tuple.h> 19#include <net/netfilter/nf_conntrack_tuple.h>
20#include <net/netfilter/nf_conntrack_helper.h> 20#include <net/netfilter/nf_conntrack_helper.h>
21#include <net/netfilter/nf_conntrack_ecache.h>
21 22
22struct nft_ct { 23struct nft_ct {
23 enum nft_ct_keys key:8; 24 enum nft_ct_keys key:8;
24 enum ip_conntrack_dir dir:8; 25 enum ip_conntrack_dir dir:8;
25 enum nft_registers dreg:8; 26 union{
27 enum nft_registers dreg:8;
28 enum nft_registers sreg:8;
29 };
26 uint8_t family; 30 uint8_t family;
27}; 31};
28 32
29static void nft_ct_eval(const struct nft_expr *expr, 33static void nft_ct_get_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1], 34 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt) 35 const struct nft_pktinfo *pkt)
32{ 36{
33 const struct nft_ct *priv = nft_expr_priv(expr); 37 const struct nft_ct *priv = nft_expr_priv(expr);
34 struct nft_data *dest = &data[priv->dreg]; 38 struct nft_data *dest = &data[priv->dreg];
@@ -123,24 +127,77 @@ err:
123 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 127 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
124} 128}
125 129
130static void nft_ct_set_eval(const struct nft_expr *expr,
131 struct nft_data data[NFT_REG_MAX + 1],
132 const struct nft_pktinfo *pkt)
133{
134 const struct nft_ct *priv = nft_expr_priv(expr);
135 struct sk_buff *skb = pkt->skb;
136 u32 value = data[priv->sreg].data[0];
137 enum ip_conntrack_info ctinfo;
138 struct nf_conn *ct;
139
140 ct = nf_ct_get(skb, &ctinfo);
141 if (ct == NULL)
142 return;
143
144 switch (priv->key) {
145#ifdef CONFIG_NF_CONNTRACK_MARK
146 case NFT_CT_MARK:
147 if (ct->mark != value) {
148 ct->mark = value;
149 nf_conntrack_event_cache(IPCT_MARK, ct);
150 }
151 break;
152#endif
153 }
154}
155
126static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { 156static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
127 [NFTA_CT_DREG] = { .type = NLA_U32 }, 157 [NFTA_CT_DREG] = { .type = NLA_U32 },
128 [NFTA_CT_KEY] = { .type = NLA_U32 }, 158 [NFTA_CT_KEY] = { .type = NLA_U32 },
129 [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, 159 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
160 [NFTA_CT_SREG] = { .type = NLA_U32 },
130}; 161};
131 162
132static int nft_ct_init(const struct nft_ctx *ctx, 163static int nft_ct_l3proto_try_module_get(uint8_t family)
133 const struct nft_expr *expr,
134 const struct nlattr * const tb[])
135{ 164{
136 struct nft_ct *priv = nft_expr_priv(expr);
137 int err; 165 int err;
138 166
139 if (tb[NFTA_CT_DREG] == NULL || 167 if (family == NFPROTO_INET) {
140 tb[NFTA_CT_KEY] == NULL) 168 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4);
141 return -EINVAL; 169 if (err < 0)
170 goto err1;
171 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6);
172 if (err < 0)
173 goto err2;
174 } else {
175 err = nf_ct_l3proto_try_module_get(family);
176 if (err < 0)
177 goto err1;
178 }
179 return 0;
180
181err2:
182 nf_ct_l3proto_module_put(NFPROTO_IPV4);
183err1:
184 return err;
185}
186
187static void nft_ct_l3proto_module_put(uint8_t family)
188{
189 if (family == NFPROTO_INET) {
190 nf_ct_l3proto_module_put(NFPROTO_IPV4);
191 nf_ct_l3proto_module_put(NFPROTO_IPV6);
192 } else
193 nf_ct_l3proto_module_put(family);
194}
195
196static int nft_ct_init_validate_get(const struct nft_expr *expr,
197 const struct nlattr * const tb[])
198{
199 struct nft_ct *priv = nft_expr_priv(expr);
142 200
143 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
144 if (tb[NFTA_CT_DIRECTION] != NULL) { 201 if (tb[NFTA_CT_DIRECTION] != NULL) {
145 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); 202 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
146 switch (priv->dir) { 203 switch (priv->dir) {
@@ -179,34 +236,72 @@ static int nft_ct_init(const struct nft_ctx *ctx,
179 return -EOPNOTSUPP; 236 return -EOPNOTSUPP;
180 } 237 }
181 238
182 err = nf_ct_l3proto_try_module_get(ctx->afi->family); 239 return 0;
240}
241
242static int nft_ct_init_validate_set(uint32_t key)
243{
244 switch (key) {
245 case NFT_CT_MARK:
246 break;
247 default:
248 return -EOPNOTSUPP;
249 }
250
251 return 0;
252}
253
254static int nft_ct_init(const struct nft_ctx *ctx,
255 const struct nft_expr *expr,
256 const struct nlattr * const tb[])
257{
258 struct nft_ct *priv = nft_expr_priv(expr);
259 int err;
260
261 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
262
263 if (tb[NFTA_CT_DREG]) {
264 err = nft_ct_init_validate_get(expr, tb);
265 if (err < 0)
266 return err;
267
268 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
269 err = nft_validate_output_register(priv->dreg);
270 if (err < 0)
271 return err;
272
273 err = nft_validate_data_load(ctx, priv->dreg, NULL,
274 NFT_DATA_VALUE);
275 if (err < 0)
276 return err;
277 } else {
278 err = nft_ct_init_validate_set(priv->key);
279 if (err < 0)
280 return err;
281
282 priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG]));
283 err = nft_validate_input_register(priv->sreg);
284 if (err < 0)
285 return err;
286 }
287
288 err = nft_ct_l3proto_try_module_get(ctx->afi->family);
183 if (err < 0) 289 if (err < 0)
184 return err; 290 return err;
185 priv->family = ctx->afi->family;
186 291
187 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); 292 priv->family = ctx->afi->family;
188 err = nft_validate_output_register(priv->dreg);
189 if (err < 0)
190 goto err1;
191 293
192 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
193 if (err < 0)
194 goto err1;
195 return 0; 294 return 0;
196
197err1:
198 nf_ct_l3proto_module_put(ctx->afi->family);
199 return err;
200} 295}
201 296
202static void nft_ct_destroy(const struct nft_expr *expr) 297static void nft_ct_destroy(const struct nft_expr *expr)
203{ 298{
204 struct nft_ct *priv = nft_expr_priv(expr); 299 struct nft_ct *priv = nft_expr_priv(expr);
205 300
206 nf_ct_l3proto_module_put(priv->family); 301 nft_ct_l3proto_module_put(priv->family);
207} 302}
208 303
209static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr) 304static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
210{ 305{
211 const struct nft_ct *priv = nft_expr_priv(expr); 306 const struct nft_ct *priv = nft_expr_priv(expr);
212 307
@@ -222,19 +317,61 @@ nla_put_failure:
222 return -1; 317 return -1;
223} 318}
224 319
320static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
321{
322 const struct nft_ct *priv = nft_expr_priv(expr);
323
324 if (nla_put_be32(skb, NFTA_CT_SREG, htonl(priv->sreg)))
325 goto nla_put_failure;
326 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
327 goto nla_put_failure;
328 return 0;
329
330nla_put_failure:
331 return -1;
332}
333
225static struct nft_expr_type nft_ct_type; 334static struct nft_expr_type nft_ct_type;
226static const struct nft_expr_ops nft_ct_ops = { 335static const struct nft_expr_ops nft_ct_get_ops = {
227 .type = &nft_ct_type, 336 .type = &nft_ct_type,
228 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), 337 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
229 .eval = nft_ct_eval, 338 .eval = nft_ct_get_eval,
230 .init = nft_ct_init, 339 .init = nft_ct_init,
231 .destroy = nft_ct_destroy, 340 .destroy = nft_ct_destroy,
232 .dump = nft_ct_dump, 341 .dump = nft_ct_get_dump,
233}; 342};
234 343
344static const struct nft_expr_ops nft_ct_set_ops = {
345 .type = &nft_ct_type,
346 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
347 .eval = nft_ct_set_eval,
348 .init = nft_ct_init,
349 .destroy = nft_ct_destroy,
350 .dump = nft_ct_set_dump,
351};
352
353static const struct nft_expr_ops *
354nft_ct_select_ops(const struct nft_ctx *ctx,
355 const struct nlattr * const tb[])
356{
357 if (tb[NFTA_CT_KEY] == NULL)
358 return ERR_PTR(-EINVAL);
359
360 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
361 return ERR_PTR(-EINVAL);
362
363 if (tb[NFTA_CT_DREG])
364 return &nft_ct_get_ops;
365
366 if (tb[NFTA_CT_SREG])
367 return &nft_ct_set_ops;
368
369 return ERR_PTR(-EINVAL);
370}
371
235static struct nft_expr_type nft_ct_type __read_mostly = { 372static struct nft_expr_type nft_ct_type __read_mostly = {
236 .name = "ct", 373 .name = "ct",
237 .ops = &nft_ct_ops, 374 .select_ops = &nft_ct_select_ops,
238 .policy = nft_ct_policy, 375 .policy = nft_ct_policy,
239 .maxattr = NFTA_CT_MAX, 376 .maxattr = NFTA_CT_MAX,
240 .owner = THIS_MODULE, 377 .owner = THIS_MODULE,
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c
index 57cad072a13e..5af790123ad8 100644
--- a/net/netfilter/nft_log.c
+++ b/net/netfilter/nft_log.c
@@ -33,7 +33,7 @@ static void nft_log_eval(const struct nft_expr *expr,
33 const struct nft_log *priv = nft_expr_priv(expr); 33 const struct nft_log *priv = nft_expr_priv(expr);
34 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); 34 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
35 35
36 nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in, 36 nf_log_packet(net, priv->family, pkt->ops->hooknum, pkt->skb, pkt->in,
37 pkt->out, &priv->loginfo, "%s", priv->prefix); 37 pkt->out, &priv->loginfo, "%s", priv->prefix);
38} 38}
39 39
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 1ceaaa6dfe72..e8254ad2e5a9 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -43,6 +43,12 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
43 case NFT_META_PROTOCOL: 43 case NFT_META_PROTOCOL:
44 *(__be16 *)dest->data = skb->protocol; 44 *(__be16 *)dest->data = skb->protocol;
45 break; 45 break;
46 case NFT_META_NFPROTO:
47 dest->data[0] = pkt->ops->pf;
48 break;
49 case NFT_META_L4PROTO:
50 dest->data[0] = pkt->tprot;
51 break;
46 case NFT_META_PRIORITY: 52 case NFT_META_PRIORITY:
47 dest->data[0] = skb->priority; 53 dest->data[0] = skb->priority;
48 break; 54 break;
@@ -181,6 +187,8 @@ static int nft_meta_init_validate_get(uint32_t key)
181 switch (key) { 187 switch (key) {
182 case NFT_META_LEN: 188 case NFT_META_LEN:
183 case NFT_META_PROTOCOL: 189 case NFT_META_PROTOCOL:
190 case NFT_META_NFPROTO:
191 case NFT_META_L4PROTO:
184 case NFT_META_PRIORITY: 192 case NFT_META_PRIORITY:
185 case NFT_META_MARK: 193 case NFT_META_MARK:
186 case NFT_META_IIF: 194 case NFT_META_IIF:
@@ -231,6 +239,9 @@ static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
231 return err; 239 return err;
232 240
233 priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); 241 priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG]));
242 err = nft_validate_input_register(priv->sreg);
243 if (err < 0)
244 return err;
234 245
235 return 0; 246 return 0;
236} 247}
diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c
index 0d690d4101d2..5e204711d704 100644
--- a/net/netfilter/nft_reject.c
+++ b/net/netfilter/nft_reject.c
@@ -34,8 +34,9 @@ static void nft_reject_eval(const struct nft_expr *expr,
34 const struct nft_pktinfo *pkt) 34 const struct nft_pktinfo *pkt)
35{ 35{
36 struct nft_reject *priv = nft_expr_priv(expr); 36 struct nft_reject *priv = nft_expr_priv(expr);
37#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
37 struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); 38 struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
38 39#endif
39 switch (priv->type) { 40 switch (priv->type) {
40 case NFT_REJECT_ICMP_UNREACH: 41 case NFT_REJECT_ICMP_UNREACH:
41 if (priv->family == NFPROTO_IPV4) 42 if (priv->family == NFPROTO_IPV4)
@@ -43,15 +44,15 @@ static void nft_reject_eval(const struct nft_expr *expr,
43#if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 44#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
44 else if (priv->family == NFPROTO_IPV6) 45 else if (priv->family == NFPROTO_IPV6)
45 nf_send_unreach6(net, pkt->skb, priv->icmp_code, 46 nf_send_unreach6(net, pkt->skb, priv->icmp_code,
46 pkt->hooknum); 47 pkt->ops->hooknum);
47#endif 48#endif
48 break; 49 break;
49 case NFT_REJECT_TCP_RST: 50 case NFT_REJECT_TCP_RST:
50 if (priv->family == NFPROTO_IPV4) 51 if (priv->family == NFPROTO_IPV4)
51 nf_send_reset(pkt->skb, pkt->hooknum); 52 nf_send_reset(pkt->skb, pkt->ops->hooknum);
52#if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 53#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
53 else if (priv->family == NFPROTO_IPV6) 54 else if (priv->family == NFPROTO_IPV6)
54 nf_send_reset6(net, pkt->skb, pkt->hooknum); 55 nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
55#endif 56#endif
56 break; 57 break;
57 } 58 }