aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-10-17 15:22:05 -0400
committerDavid S. Miller <davem@davemloft.net>2013-10-17 15:22:05 -0400
commitda33edccebcc36d387423dcdb557094fbda55994 (patch)
tree9f426a52f875169ae24e54a395beedc697c96e02 /net
parent78dea8cc4942c6adbcccc8f483463906a078f039 (diff)
parented683f138b3dbc8a5e878e24a0bfa0bb61043a09 (diff)
Merge branch 'net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nftables
Pablo Neira Ayuso says: ==================== netfilter updates: nf_tables pull request The following patchset contains the current original nf_tables tree condensed in 17 patches. I have organized them by chronogical order since the original nf_tables code was released in 2009 and by dependencies between the different patches. The patches are: 1) Adapt all existing hooks in the tree to pass hook ops to the hook callback function, required by nf_tables, from Patrick McHardy. 2) Move alloc_null_binding to nf_nat_core, as it is now also needed by nf_tables and ip_tables, original patch from Patrick McHardy but required major changes to adapt it to the current tree that I made. 3) Add nf_tables core, including the netlink API, the packet filtering engine, expressions and built-in tables, from Patrick McHardy. This patch includes accumulated fixes since 2009 and minor enhancements. The patch description contains a list of references to the original patches for the record. For those that are not familiar to the original work, see [1], [2] and [3]. 4) Add netlink set API, this replaces the original set infrastructure to introduce a netlink API to add/delete sets and to add/delete set elements. This includes two set types: the hash and the rb-tree sets (used for interval based matching). The main difference with ipset is that this infrastructure is data type agnostic. Patch from Patrick McHardy. 5) Allow expression operation overload, this API change allows us to provide define expression subtypes depending on the configuration that is received from user-space via Netlink. It is used by follow up patches to provide optimized versions of the payload and cmp expressions and the x_tables compatibility layer, from Patrick McHardy. 6) Add optimized data comparison operation, it requires the previous patch, from Patrick McHardy. 7) Add optimized payload implementation, it requires patch 5, from Patrick McHardy. 8) Convert built-in tables to chain types. Each chain type have special semantics (filter, route and nat) that are used by userspace to configure the chain behaviour. The main chain regarding iptables is that tables become containers of chain, with no specific semantics. However, you may still configure your tables and chains to retain iptables like semantics, patch from me. 9) Add compatibility layer for x_tables. This patch adds support to use all existing x_tables extensions from nf_tables, this is used to provide a userspace utility that accepts iptables syntax but used internally the nf_tables kernel core. This patch includes missing features in the nf_tables core such as the per-chain stats, default chain policy and number of chain references, which are required by the iptables compatibility userspace tool. Patch from me. 10) Fix transport protocol matching, this fix is a side effect of the x_tables compatibility layer, which now provides a pointer to the transport header, from me. 11) Add support for dormant tables, this feature allows you to disable all chains and rules that are contained in one table, from me. 12) Add IPv6 NAT support. At the time nf_tables was made, there was no NAT IPv6 support yet, from Tomasz Bursztyka. 13) Complete net namespace support. This patch register the protocol family per net namespace, so tables (thus, other objects contained in tables such as sets, chains and rules) are only visible from the corresponding net namespace, from me. 14) Add the insert operation to the nf_tables netlink API, this requires adding a new position attribute that allow us to locate where in the ruleset a rule needs to be inserted, from Eric Leblond. 15) Add rule batching support, including atomic rule-set updates by using rule-set generations. This patch includes a change to nfnetlink to include two new control messages to indicate the beginning and the end of a batch. The end message is interpreted as the commit message, if it's missing, then the rule-set updates contained in the batch are aborted, from me. 16) Add trace support to the nf_tables packet filtering core, from me. 17) Add ARP filtering support, original patch from Patrick McHardy, but adapted to fit into the chain type infrastructure. This was recovered to be used by nft userspace tool and our compatibility arptables userspace tool. There is still work to do to fully replace x_tables [4] [5] but that can be done incrementally by extending our netlink API. Moreover, looking at netfilter-devel and the amount of contributions to nf_tables we've been getting, I think it would be good to have it mainstream to avoid accumulating large patchsets skip continuous rebases. I tried to provide a reasonable patchset, we have more than 100 accumulated patches in the original nf_tables tree, so I collapsed many of the small fixes to the main patch we had since 2009 and provide a small batch for review to netdev, while trying to retain part of the history. For those who didn't give a try to nf_tables yet, there's a quick howto available from Eric Leblond that describes how to get things working [6]. Comments/reviews welcome. Thanks! [1] http://lwn.net/Articles/324251/ [2] http://workshop.netfilter.org/2013/wiki/images/e/ee/Nftables-osd-2013-developer.pdf [3] http://lwn.net/Articles/564095/ [4] http://people.netfilter.org/pablo/map-pending-work.txt [4] http://people.netfilter.org/pablo/nftables-todo.txt [5] https://home.regit.org/netfilter-en/nftables-quick-howto/ ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netfilter.c22
-rw-r--r--net/bridge/netfilter/Kconfig3
-rw-r--r--net/bridge/netfilter/Makefile2
-rw-r--r--net/bridge/netfilter/ebtable_filter.c16
-rw-r--r--net/bridge/netfilter/ebtable_nat.c16
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c65
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c2
-rw-r--r--net/ipv4/netfilter/Kconfig21
-rw-r--r--net/ipv4/netfilter/Makefile6
-rw-r--r--net/ipv4/netfilter/arptable_filter.c5
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c2
-rw-r--r--net/ipv4/netfilter/ipt_SYNPROXY.c2
-rw-r--r--net/ipv4/netfilter/iptable_filter.c7
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c10
-rw-r--r--net/ipv4/netfilter/iptable_nat.c26
-rw-r--r--net/ipv4/netfilter/iptable_raw.c6
-rw-r--r--net/ipv4/netfilter/iptable_security.c7
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c12
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c6
-rw-r--r--net/ipv4/netfilter/nf_tables_arp.c102
-rw-r--r--net/ipv4/netfilter/nf_tables_ipv4.c128
-rw-r--r--net/ipv4/netfilter/nft_chain_nat_ipv4.c205
-rw-r--r--net/ipv4/netfilter/nft_chain_route_ipv4.c90
-rw-r--r--net/ipv4/netfilter/nft_reject_ipv4.c123
-rw-r--r--net/ipv6/netfilter/Kconfig13
-rw-r--r--net/ipv6/netfilter/Makefile5
-rw-r--r--net/ipv6/netfilter/ip6t_SYNPROXY.c2
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c5
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c10
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c27
-rw-r--r--net/ipv6/netfilter/ip6table_raw.c5
-rw-r--r--net/ipv6/netfilter/ip6table_security.c5
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c14
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c6
-rw-r--r--net/ipv6/netfilter/nf_tables_ipv6.c127
-rw-r--r--net/ipv6/netfilter/nft_chain_nat_ipv6.c211
-rw-r--r--net/ipv6/netfilter/nft_chain_route_ipv6.c88
-rw-r--r--net/netfilter/Kconfig52
-rw-r--r--net/netfilter/Makefile18
-rw-r--r--net/netfilter/core.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c42
-rw-r--r--net/netfilter/nf_nat_core.c20
-rw-r--r--net/netfilter/nf_tables_api.c3275
-rw-r--r--net/netfilter/nf_tables_core.c270
-rw-r--r--net/netfilter/nfnetlink.c175
-rw-r--r--net/netfilter/nft_bitwise.c146
-rw-r--r--net/netfilter/nft_byteorder.c173
-rw-r--r--net/netfilter/nft_cmp.c223
-rw-r--r--net/netfilter/nft_compat.c768
-rw-r--r--net/netfilter/nft_counter.c113
-rw-r--r--net/netfilter/nft_ct.c258
-rw-r--r--net/netfilter/nft_expr_template.c94
-rw-r--r--net/netfilter/nft_exthdr.c133
-rw-r--r--net/netfilter/nft_hash.c231
-rw-r--r--net/netfilter/nft_immediate.c132
-rw-r--r--net/netfilter/nft_limit.c119
-rw-r--r--net/netfilter/nft_log.c146
-rw-r--r--net/netfilter/nft_lookup.c141
-rw-r--r--net/netfilter/nft_meta.c228
-rw-r--r--net/netfilter/nft_meta_target.c117
-rw-r--r--net/netfilter/nft_nat.c220
-rw-r--r--net/netfilter/nft_payload.c160
-rw-r--r--net/netfilter/nft_rbtree.c247
63 files changed, 8785 insertions, 120 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index f87736270eaa..878f008afefa 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -619,7 +619,7 @@ bad:
619 619
620/* Replicate the checks that IPv6 does on packet reception and pass the packet 620/* Replicate the checks that IPv6 does on packet reception and pass the packet
621 * to ip6tables, which doesn't support NAT, so things are fairly simple. */ 621 * to ip6tables, which doesn't support NAT, so things are fairly simple. */
622static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, 622static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
623 struct sk_buff *skb, 623 struct sk_buff *skb,
624 const struct net_device *in, 624 const struct net_device *in,
625 const struct net_device *out, 625 const struct net_device *out,
@@ -669,7 +669,8 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
669 * receiving device) to make netfilter happy, the REDIRECT 669 * receiving device) to make netfilter happy, the REDIRECT
670 * target in particular. Save the original destination IP 670 * target in particular. Save the original destination IP
671 * address to be able to detect DNAT afterwards. */ 671 * address to be able to detect DNAT afterwards. */
672static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, 672static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
673 struct sk_buff *skb,
673 const struct net_device *in, 674 const struct net_device *in,
674 const struct net_device *out, 675 const struct net_device *out,
675 int (*okfn)(struct sk_buff *)) 676 int (*okfn)(struct sk_buff *))
@@ -691,7 +692,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
691 return NF_ACCEPT; 692 return NF_ACCEPT;
692 693
693 nf_bridge_pull_encap_header_rcsum(skb); 694 nf_bridge_pull_encap_header_rcsum(skb);
694 return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); 695 return br_nf_pre_routing_ipv6(ops, skb, in, out, okfn);
695 } 696 }
696 697
697 if (!brnf_call_iptables && !br->nf_call_iptables) 698 if (!brnf_call_iptables && !br->nf_call_iptables)
@@ -727,7 +728,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
727 * took place when the packet entered the bridge), but we 728 * took place when the packet entered the bridge), but we
728 * register an IPv4 PRE_ROUTING 'sabotage' hook that will 729 * register an IPv4 PRE_ROUTING 'sabotage' hook that will
729 * prevent this from happening. */ 730 * prevent this from happening. */
730static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, 731static unsigned int br_nf_local_in(const struct nf_hook_ops *ops,
732 struct sk_buff *skb,
731 const struct net_device *in, 733 const struct net_device *in,
732 const struct net_device *out, 734 const struct net_device *out,
733 int (*okfn)(struct sk_buff *)) 735 int (*okfn)(struct sk_buff *))
@@ -765,7 +767,8 @@ static int br_nf_forward_finish(struct sk_buff *skb)
765 * but we are still able to filter on the 'real' indev/outdev 767 * but we are still able to filter on the 'real' indev/outdev
766 * because of the physdev module. For ARP, indev and outdev are the 768 * because of the physdev module. For ARP, indev and outdev are the
767 * bridge ports. */ 769 * bridge ports. */
768static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, 770static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops,
771 struct sk_buff *skb,
769 const struct net_device *in, 772 const struct net_device *in,
770 const struct net_device *out, 773 const struct net_device *out,
771 int (*okfn)(struct sk_buff *)) 774 int (*okfn)(struct sk_buff *))
@@ -818,7 +821,8 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
818 return NF_STOLEN; 821 return NF_STOLEN;
819} 822}
820 823
821static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb, 824static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops,
825 struct sk_buff *skb,
822 const struct net_device *in, 826 const struct net_device *in,
823 const struct net_device *out, 827 const struct net_device *out,
824 int (*okfn)(struct sk_buff *)) 828 int (*okfn)(struct sk_buff *))
@@ -878,7 +882,8 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb)
878#endif 882#endif
879 883
880/* PF_BRIDGE/POST_ROUTING ********************************************/ 884/* PF_BRIDGE/POST_ROUTING ********************************************/
881static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, 885static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops,
886 struct sk_buff *skb,
882 const struct net_device *in, 887 const struct net_device *in,
883 const struct net_device *out, 888 const struct net_device *out,
884 int (*okfn)(struct sk_buff *)) 889 int (*okfn)(struct sk_buff *))
@@ -923,7 +928,8 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
923/* IP/SABOTAGE *****************************************************/ 928/* IP/SABOTAGE *****************************************************/
924/* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING 929/* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
925 * for the second time. */ 930 * for the second time. */
926static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb, 931static unsigned int ip_sabotage_in(const struct nf_hook_ops *ops,
932 struct sk_buff *skb,
927 const struct net_device *in, 933 const struct net_device *in,
928 const struct net_device *out, 934 const struct net_device *out,
929 int (*okfn)(struct sk_buff *)) 935 int (*okfn)(struct sk_buff *))
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index a9aff9c7d027..68f8128147be 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -1,6 +1,9 @@
1# 1#
2# Bridge netfilter configuration 2# Bridge netfilter configuration
3# 3#
4#
5config NF_TABLES_BRIDGE
6 tristate "Ethernet Bridge nf_tables support"
4 7
5menuconfig BRIDGE_NF_EBTABLES 8menuconfig BRIDGE_NF_EBTABLES
6 tristate "Ethernet Bridge tables (ebtables) support" 9 tristate "Ethernet Bridge tables (ebtables) support"
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
index 0718699540b0..ea7629f58b3d 100644
--- a/net/bridge/netfilter/Makefile
+++ b/net/bridge/netfilter/Makefile
@@ -2,6 +2,8 @@
2# Makefile for the netfilter modules for Link Layer filtering on a bridge. 2# Makefile for the netfilter modules for Link Layer filtering on a bridge.
3# 3#
4 4
5obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o
6
5obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o 7obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
6 8
7# tables 9# tables
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 94b2b700cff8..bb2da7b706e7 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -60,17 +60,21 @@ static const struct ebt_table frame_filter =
60}; 60};
61 61
62static unsigned int 62static unsigned int
63ebt_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, 63ebt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
64 const struct net_device *out, int (*okfn)(struct sk_buff *)) 64 const struct net_device *in, const struct net_device *out,
65 int (*okfn)(struct sk_buff *))
65{ 66{
66 return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_filter); 67 return ebt_do_table(ops->hooknum, skb, in, out,
68 dev_net(in)->xt.frame_filter);
67} 69}
68 70
69static unsigned int 71static unsigned int
70ebt_out_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, 72ebt_out_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
71 const struct net_device *out, int (*okfn)(struct sk_buff *)) 73 const struct net_device *in, const struct net_device *out,
74 int (*okfn)(struct sk_buff *))
72{ 75{
73 return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_filter); 76 return ebt_do_table(ops->hooknum, skb, in, out,
77 dev_net(out)->xt.frame_filter);
74} 78}
75 79
76static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { 80static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 322555acdd40..bd238f1f105b 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -60,17 +60,21 @@ static struct ebt_table frame_nat =
60}; 60};
61 61
62static unsigned int 62static unsigned int
63ebt_nat_in(unsigned int hook, struct sk_buff *skb, const struct net_device *in 63ebt_nat_in(const struct nf_hook_ops *ops, struct sk_buff *skb,
64 , const struct net_device *out, int (*okfn)(struct sk_buff *)) 64 const struct net_device *in, const struct net_device *out,
65 int (*okfn)(struct sk_buff *))
65{ 66{
66 return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_nat); 67 return ebt_do_table(ops->hooknum, skb, in, out,
68 dev_net(in)->xt.frame_nat);
67} 69}
68 70
69static unsigned int 71static unsigned int
70ebt_nat_out(unsigned int hook, struct sk_buff *skb, const struct net_device *in 72ebt_nat_out(const struct nf_hook_ops *ops, struct sk_buff *skb,
71 , const struct net_device *out, int (*okfn)(struct sk_buff *)) 73 const struct net_device *in, const struct net_device *out,
74 int (*okfn)(struct sk_buff *))
72{ 75{
73 return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_nat); 76 return ebt_do_table(ops->hooknum, skb, in, out,
77 dev_net(out)->xt.frame_nat);
74} 78}
75 79
76static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { 80static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c
new file mode 100644
index 000000000000..e8cb016fa34d
--- /dev/null
+++ b/net/bridge/netfilter/nf_tables_bridge.c
@@ -0,0 +1,65 @@
1/*
2 * Copyright (c) 2008 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/init.h>
12#include <linux/module.h>
13#include <linux/netfilter_bridge.h>
14#include <net/netfilter/nf_tables.h>
15
16static struct nft_af_info nft_af_bridge __read_mostly = {
17 .family = NFPROTO_BRIDGE,
18 .nhooks = NF_BR_NUMHOOKS,
19 .owner = THIS_MODULE,
20};
21
22static int nf_tables_bridge_init_net(struct net *net)
23{
24 net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
25 if (net->nft.bridge == NULL)
26 return -ENOMEM;
27
28 memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge));
29
30 if (nft_register_afinfo(net, net->nft.bridge) < 0)
31 goto err;
32
33 return 0;
34err:
35 kfree(net->nft.bridge);
36 return -ENOMEM;
37}
38
39static void nf_tables_bridge_exit_net(struct net *net)
40{
41 nft_unregister_afinfo(net->nft.bridge);
42 kfree(net->nft.bridge);
43}
44
45static struct pernet_operations nf_tables_bridge_net_ops = {
46 .init = nf_tables_bridge_init_net,
47 .exit = nf_tables_bridge_exit_net,
48};
49
50static int __init nf_tables_bridge_init(void)
51{
52 return register_pernet_subsys(&nf_tables_bridge_net_ops);
53}
54
55static void __exit nf_tables_bridge_exit(void)
56{
57 return unregister_pernet_subsys(&nf_tables_bridge_net_ops);
58}
59
60module_init(nf_tables_bridge_init);
61module_exit(nf_tables_bridge_exit);
62
63MODULE_LICENSE("GPL");
64MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
65MODULE_ALIAS_NFT_FAMILY(AF_BRIDGE);
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 2a7efe388344..e83015cecfa7 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -87,7 +87,7 @@ static void dnrmg_send_peer(struct sk_buff *skb)
87} 87}
88 88
89 89
90static unsigned int dnrmg_hook(unsigned int hook, 90static unsigned int dnrmg_hook(const struct nf_hook_ops *ops,
91 struct sk_buff *skb, 91 struct sk_buff *skb,
92 const struct net_device *in, 92 const struct net_device *in,
93 const struct net_device *out, 93 const struct net_device *out,
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1657e39b291f..40d56073cd19 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -36,6 +36,27 @@ config NF_CONNTRACK_PROC_COMPAT
36 36
37 If unsure, say Y. 37 If unsure, say Y.
38 38
39config NF_TABLES_IPV4
40 depends on NF_TABLES
41 tristate "IPv4 nf_tables support"
42
43config NFT_REJECT_IPV4
44 depends on NF_TABLES_IPV4
45 tristate "nf_tables IPv4 reject support"
46
47config NFT_CHAIN_ROUTE_IPV4
48 depends on NF_TABLES_IPV4
49 tristate "IPv4 nf_tables route chain support"
50
51config NFT_CHAIN_NAT_IPV4
52 depends on NF_TABLES_IPV4
53 depends on NF_NAT_IPV4 && NFT_NAT
54 tristate "IPv4 nf_tables nat chain support"
55
56config NF_TABLES_ARP
57 depends on NF_TABLES
58 tristate "ARP nf_tables support"
59
39config IP_NF_IPTABLES 60config IP_NF_IPTABLES
40 tristate "IP tables support (required for filtering/masq/NAT)" 61 tristate "IP tables support (required for filtering/masq/NAT)"
41 default m if NETFILTER_ADVANCED=n 62 default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 3622b248b6dd..19df72b7ba88 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -27,6 +27,12 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
27# NAT protocols (nf_nat) 27# NAT protocols (nf_nat)
28obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 28obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
29 29
30obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
31obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
32obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
33obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
34obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
35
30# generic IP tables 36# generic IP tables
31obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 37obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
32 38
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index a865f6f94013..802ddecb30b8 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -27,13 +27,14 @@ static const struct xt_table packet_filter = {
27 27
28/* The work comes in here from netfilter.c */ 28/* The work comes in here from netfilter.c */
29static unsigned int 29static unsigned int
30arptable_filter_hook(unsigned int hook, struct sk_buff *skb, 30arptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
31 const struct net_device *in, const struct net_device *out, 31 const struct net_device *in, const struct net_device *out,
32 int (*okfn)(struct sk_buff *)) 32 int (*okfn)(struct sk_buff *))
33{ 33{
34 const struct net *net = dev_net((in != NULL) ? in : out); 34 const struct net *net = dev_net((in != NULL) ? in : out);
35 35
36 return arpt_do_table(skb, hook, in, out, net->ipv4.arptable_filter); 36 return arpt_do_table(skb, ops->hooknum, in, out,
37 net->ipv4.arptable_filter);
37} 38}
38 39
39static struct nf_hook_ops *arpfilter_ops __read_mostly; 40static struct nf_hook_ops *arpfilter_ops __read_mostly;
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 0b732efd32e2..a2e2b61cd7da 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -483,7 +483,7 @@ static void arp_print(struct arp_payload *payload)
483#endif 483#endif
484 484
485static unsigned int 485static unsigned int
486arp_mangle(unsigned int hook, 486arp_mangle(const struct nf_hook_ops *ops,
487 struct sk_buff *skb, 487 struct sk_buff *skb,
488 const struct net_device *in, 488 const struct net_device *in,
489 const struct net_device *out, 489 const struct net_device *out,
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index b6346bf2fde3..01cffeaa0085 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -297,7 +297,7 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
297 return XT_CONTINUE; 297 return XT_CONTINUE;
298} 298}
299 299
300static unsigned int ipv4_synproxy_hook(unsigned int hooknum, 300static unsigned int ipv4_synproxy_hook(const struct nf_hook_ops *ops,
301 struct sk_buff *skb, 301 struct sk_buff *skb,
302 const struct net_device *in, 302 const struct net_device *in,
303 const struct net_device *out, 303 const struct net_device *out,
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 50af5b45c050..e08a74a243a8 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -33,20 +33,21 @@ static const struct xt_table packet_filter = {
33}; 33};
34 34
35static unsigned int 35static unsigned int
36iptable_filter_hook(unsigned int hook, struct sk_buff *skb, 36iptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
37 const struct net_device *in, const struct net_device *out, 37 const struct net_device *in, const struct net_device *out,
38 int (*okfn)(struct sk_buff *)) 38 int (*okfn)(struct sk_buff *))
39{ 39{
40 const struct net *net; 40 const struct net *net;
41 41
42 if (hook == NF_INET_LOCAL_OUT && 42 if (ops->hooknum == NF_INET_LOCAL_OUT &&
43 (skb->len < sizeof(struct iphdr) || 43 (skb->len < sizeof(struct iphdr) ||
44 ip_hdrlen(skb) < sizeof(struct iphdr))) 44 ip_hdrlen(skb) < sizeof(struct iphdr)))
45 /* root is playing with raw sockets. */ 45 /* root is playing with raw sockets. */
46 return NF_ACCEPT; 46 return NF_ACCEPT;
47 47
48 net = dev_net((in != NULL) ? in : out); 48 net = dev_net((in != NULL) ? in : out);
49 return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_filter); 49 return ipt_do_table(skb, ops->hooknum, in, out,
50 net->ipv4.iptable_filter);
50} 51}
51 52
52static struct nf_hook_ops *filter_ops __read_mostly; 53static struct nf_hook_ops *filter_ops __read_mostly;
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 0d8cd82e0fad..6a5079c34bb3 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -79,19 +79,19 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out)
79 79
80/* The work comes in here from netfilter.c. */ 80/* The work comes in here from netfilter.c. */
81static unsigned int 81static unsigned int
82iptable_mangle_hook(unsigned int hook, 82iptable_mangle_hook(const struct nf_hook_ops *ops,
83 struct sk_buff *skb, 83 struct sk_buff *skb,
84 const struct net_device *in, 84 const struct net_device *in,
85 const struct net_device *out, 85 const struct net_device *out,
86 int (*okfn)(struct sk_buff *)) 86 int (*okfn)(struct sk_buff *))
87{ 87{
88 if (hook == NF_INET_LOCAL_OUT) 88 if (ops->hooknum == NF_INET_LOCAL_OUT)
89 return ipt_mangle_out(skb, out); 89 return ipt_mangle_out(skb, out);
90 if (hook == NF_INET_POST_ROUTING) 90 if (ops->hooknum == NF_INET_POST_ROUTING)
91 return ipt_do_table(skb, hook, in, out, 91 return ipt_do_table(skb, ops->hooknum, in, out,
92 dev_net(out)->ipv4.iptable_mangle); 92 dev_net(out)->ipv4.iptable_mangle);
93 /* PREROUTING/INPUT/FORWARD: */ 93 /* PREROUTING/INPUT/FORWARD: */
94 return ipt_do_table(skb, hook, in, out, 94 return ipt_do_table(skb, ops->hooknum, in, out,
95 dev_net(in)->ipv4.iptable_mangle); 95 dev_net(in)->ipv4.iptable_mangle);
96} 96}
97 97
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index 683bfaffed65..ee2886126e3d 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -61,7 +61,7 @@ static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
61} 61}
62 62
63static unsigned int 63static unsigned int
64nf_nat_ipv4_fn(unsigned int hooknum, 64nf_nat_ipv4_fn(const struct nf_hook_ops *ops,
65 struct sk_buff *skb, 65 struct sk_buff *skb,
66 const struct net_device *in, 66 const struct net_device *in,
67 const struct net_device *out, 67 const struct net_device *out,
@@ -71,7 +71,7 @@ nf_nat_ipv4_fn(unsigned int hooknum,
71 enum ip_conntrack_info ctinfo; 71 enum ip_conntrack_info ctinfo;
72 struct nf_conn_nat *nat; 72 struct nf_conn_nat *nat;
73 /* maniptype == SRC for postrouting. */ 73 /* maniptype == SRC for postrouting. */
74 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 74 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
75 75
76 /* We never see fragments: conntrack defrags on pre-routing 76 /* We never see fragments: conntrack defrags on pre-routing
77 * and local-out, and nf_nat_out protects post-routing. 77 * and local-out, and nf_nat_out protects post-routing.
@@ -108,7 +108,7 @@ nf_nat_ipv4_fn(unsigned int hooknum,
108 case IP_CT_RELATED_REPLY: 108 case IP_CT_RELATED_REPLY:
109 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 109 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
110 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 110 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
111 hooknum)) 111 ops->hooknum))
112 return NF_DROP; 112 return NF_DROP;
113 else 113 else
114 return NF_ACCEPT; 114 return NF_ACCEPT;
@@ -121,14 +121,14 @@ nf_nat_ipv4_fn(unsigned int hooknum,
121 if (!nf_nat_initialized(ct, maniptype)) { 121 if (!nf_nat_initialized(ct, maniptype)) {
122 unsigned int ret; 122 unsigned int ret;
123 123
124 ret = nf_nat_rule_find(skb, hooknum, in, out, ct); 124 ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct);
125 if (ret != NF_ACCEPT) 125 if (ret != NF_ACCEPT)
126 return ret; 126 return ret;
127 } else { 127 } else {
128 pr_debug("Already setup manip %s for ct %p\n", 128 pr_debug("Already setup manip %s for ct %p\n",
129 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 129 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
130 ct); 130 ct);
131 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) 131 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
132 goto oif_changed; 132 goto oif_changed;
133 } 133 }
134 break; 134 break;
@@ -137,11 +137,11 @@ nf_nat_ipv4_fn(unsigned int hooknum,
137 /* ESTABLISHED */ 137 /* ESTABLISHED */
138 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 138 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
139 ctinfo == IP_CT_ESTABLISHED_REPLY); 139 ctinfo == IP_CT_ESTABLISHED_REPLY);
140 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) 140 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
141 goto oif_changed; 141 goto oif_changed;
142 } 142 }
143 143
144 return nf_nat_packet(ct, ctinfo, hooknum, skb); 144 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
145 145
146oif_changed: 146oif_changed:
147 nf_ct_kill_acct(ct, ctinfo, skb); 147 nf_ct_kill_acct(ct, ctinfo, skb);
@@ -149,7 +149,7 @@ oif_changed:
149} 149}
150 150
151static unsigned int 151static unsigned int
152nf_nat_ipv4_in(unsigned int hooknum, 152nf_nat_ipv4_in(const struct nf_hook_ops *ops,
153 struct sk_buff *skb, 153 struct sk_buff *skb,
154 const struct net_device *in, 154 const struct net_device *in,
155 const struct net_device *out, 155 const struct net_device *out,
@@ -158,7 +158,7 @@ nf_nat_ipv4_in(unsigned int hooknum,
158 unsigned int ret; 158 unsigned int ret;
159 __be32 daddr = ip_hdr(skb)->daddr; 159 __be32 daddr = ip_hdr(skb)->daddr;
160 160
161 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn); 161 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
162 if (ret != NF_DROP && ret != NF_STOLEN && 162 if (ret != NF_DROP && ret != NF_STOLEN &&
163 daddr != ip_hdr(skb)->daddr) 163 daddr != ip_hdr(skb)->daddr)
164 skb_dst_drop(skb); 164 skb_dst_drop(skb);
@@ -167,7 +167,7 @@ nf_nat_ipv4_in(unsigned int hooknum,
167} 167}
168 168
169static unsigned int 169static unsigned int
170nf_nat_ipv4_out(unsigned int hooknum, 170nf_nat_ipv4_out(const struct nf_hook_ops *ops,
171 struct sk_buff *skb, 171 struct sk_buff *skb,
172 const struct net_device *in, 172 const struct net_device *in,
173 const struct net_device *out, 173 const struct net_device *out,
@@ -185,7 +185,7 @@ nf_nat_ipv4_out(unsigned int hooknum,
185 ip_hdrlen(skb) < sizeof(struct iphdr)) 185 ip_hdrlen(skb) < sizeof(struct iphdr))
186 return NF_ACCEPT; 186 return NF_ACCEPT;
187 187
188 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn); 188 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
189#ifdef CONFIG_XFRM 189#ifdef CONFIG_XFRM
190 if (ret != NF_DROP && ret != NF_STOLEN && 190 if (ret != NF_DROP && ret != NF_STOLEN &&
191 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 191 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
@@ -207,7 +207,7 @@ nf_nat_ipv4_out(unsigned int hooknum,
207} 207}
208 208
209static unsigned int 209static unsigned int
210nf_nat_ipv4_local_fn(unsigned int hooknum, 210nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops,
211 struct sk_buff *skb, 211 struct sk_buff *skb,
212 const struct net_device *in, 212 const struct net_device *in,
213 const struct net_device *out, 213 const struct net_device *out,
@@ -223,7 +223,7 @@ nf_nat_ipv4_local_fn(unsigned int hooknum,
223 ip_hdrlen(skb) < sizeof(struct iphdr)) 223 ip_hdrlen(skb) < sizeof(struct iphdr))
224 return NF_ACCEPT; 224 return NF_ACCEPT;
225 225
226 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn); 226 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
227 if (ret != NF_DROP && ret != NF_STOLEN && 227 if (ret != NF_DROP && ret != NF_STOLEN &&
228 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 228 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
229 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 229 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 1f82aea11df6..b2f7e8f98316 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -20,20 +20,20 @@ static const struct xt_table packet_raw = {
20 20
21/* The work comes in here from netfilter.c. */ 21/* The work comes in here from netfilter.c. */
22static unsigned int 22static unsigned int
23iptable_raw_hook(unsigned int hook, struct sk_buff *skb, 23iptable_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
24 const struct net_device *in, const struct net_device *out, 24 const struct net_device *in, const struct net_device *out,
25 int (*okfn)(struct sk_buff *)) 25 int (*okfn)(struct sk_buff *))
26{ 26{
27 const struct net *net; 27 const struct net *net;
28 28
29 if (hook == NF_INET_LOCAL_OUT && 29 if (ops->hooknum == NF_INET_LOCAL_OUT &&
30 (skb->len < sizeof(struct iphdr) || 30 (skb->len < sizeof(struct iphdr) ||
31 ip_hdrlen(skb) < sizeof(struct iphdr))) 31 ip_hdrlen(skb) < sizeof(struct iphdr)))
32 /* root is playing with raw sockets. */ 32 /* root is playing with raw sockets. */
33 return NF_ACCEPT; 33 return NF_ACCEPT;
34 34
35 net = dev_net((in != NULL) ? in : out); 35 net = dev_net((in != NULL) ? in : out);
36 return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_raw); 36 return ipt_do_table(skb, ops->hooknum, in, out, net->ipv4.iptable_raw);
37} 37}
38 38
39static struct nf_hook_ops *rawtable_ops __read_mostly; 39static struct nf_hook_ops *rawtable_ops __read_mostly;
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index f867a8d38bf7..c86647ed2078 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -37,21 +37,22 @@ static const struct xt_table security_table = {
37}; 37};
38 38
39static unsigned int 39static unsigned int
40iptable_security_hook(unsigned int hook, struct sk_buff *skb, 40iptable_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
41 const struct net_device *in, 41 const struct net_device *in,
42 const struct net_device *out, 42 const struct net_device *out,
43 int (*okfn)(struct sk_buff *)) 43 int (*okfn)(struct sk_buff *))
44{ 44{
45 const struct net *net; 45 const struct net *net;
46 46
47 if (hook == NF_INET_LOCAL_OUT && 47 if (ops->hooknum == NF_INET_LOCAL_OUT &&
48 (skb->len < sizeof(struct iphdr) || 48 (skb->len < sizeof(struct iphdr) ||
49 ip_hdrlen(skb) < sizeof(struct iphdr))) 49 ip_hdrlen(skb) < sizeof(struct iphdr)))
50 /* Somebody is playing with raw sockets. */ 50 /* Somebody is playing with raw sockets. */
51 return NF_ACCEPT; 51 return NF_ACCEPT;
52 52
53 net = dev_net((in != NULL) ? in : out); 53 net = dev_net((in != NULL) ? in : out);
54 return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_security); 54 return ipt_do_table(skb, ops->hooknum, in, out,
55 net->ipv4.iptable_security);
55} 56}
56 57
57static struct nf_hook_ops *sectbl_ops __read_mostly; 58static struct nf_hook_ops *sectbl_ops __read_mostly;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 86f5b34a4ed1..ecd8bec411c9 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -92,7 +92,7 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
92 return NF_ACCEPT; 92 return NF_ACCEPT;
93} 93}
94 94
95static unsigned int ipv4_helper(unsigned int hooknum, 95static unsigned int ipv4_helper(const struct nf_hook_ops *ops,
96 struct sk_buff *skb, 96 struct sk_buff *skb,
97 const struct net_device *in, 97 const struct net_device *in,
98 const struct net_device *out, 98 const struct net_device *out,
@@ -121,7 +121,7 @@ static unsigned int ipv4_helper(unsigned int hooknum,
121 ct, ctinfo); 121 ct, ctinfo);
122} 122}
123 123
124static unsigned int ipv4_confirm(unsigned int hooknum, 124static unsigned int ipv4_confirm(const struct nf_hook_ops *ops,
125 struct sk_buff *skb, 125 struct sk_buff *skb,
126 const struct net_device *in, 126 const struct net_device *in,
127 const struct net_device *out, 127 const struct net_device *out,
@@ -147,16 +147,16 @@ out:
147 return nf_conntrack_confirm(skb); 147 return nf_conntrack_confirm(skb);
148} 148}
149 149
150static unsigned int ipv4_conntrack_in(unsigned int hooknum, 150static unsigned int ipv4_conntrack_in(const struct nf_hook_ops *ops,
151 struct sk_buff *skb, 151 struct sk_buff *skb,
152 const struct net_device *in, 152 const struct net_device *in,
153 const struct net_device *out, 153 const struct net_device *out,
154 int (*okfn)(struct sk_buff *)) 154 int (*okfn)(struct sk_buff *))
155{ 155{
156 return nf_conntrack_in(dev_net(in), PF_INET, hooknum, skb); 156 return nf_conntrack_in(dev_net(in), PF_INET, ops->hooknum, skb);
157} 157}
158 158
159static unsigned int ipv4_conntrack_local(unsigned int hooknum, 159static unsigned int ipv4_conntrack_local(const struct nf_hook_ops *ops,
160 struct sk_buff *skb, 160 struct sk_buff *skb,
161 const struct net_device *in, 161 const struct net_device *in,
162 const struct net_device *out, 162 const struct net_device *out,
@@ -166,7 +166,7 @@ static unsigned int ipv4_conntrack_local(unsigned int hooknum,
166 if (skb->len < sizeof(struct iphdr) || 166 if (skb->len < sizeof(struct iphdr) ||
167 ip_hdrlen(skb) < sizeof(struct iphdr)) 167 ip_hdrlen(skb) < sizeof(struct iphdr))
168 return NF_ACCEPT; 168 return NF_ACCEPT;
169 return nf_conntrack_in(dev_net(out), PF_INET, hooknum, skb); 169 return nf_conntrack_in(dev_net(out), PF_INET, ops->hooknum, skb);
170} 170}
171 171
172/* Connection tracking may drop packets, but never alters them, so 172/* Connection tracking may drop packets, but never alters them, so
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index 742815518b0f..12e13bd82b5b 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -60,7 +60,7 @@ static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
60 return IP_DEFRAG_CONNTRACK_OUT + zone; 60 return IP_DEFRAG_CONNTRACK_OUT + zone;
61} 61}
62 62
63static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 63static unsigned int ipv4_conntrack_defrag(const struct nf_hook_ops *ops,
64 struct sk_buff *skb, 64 struct sk_buff *skb,
65 const struct net_device *in, 65 const struct net_device *in,
66 const struct net_device *out, 66 const struct net_device *out,
@@ -83,7 +83,9 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
83#endif 83#endif
84 /* Gather fragments. */ 84 /* Gather fragments. */
85 if (ip_is_fragment(ip_hdr(skb))) { 85 if (ip_is_fragment(ip_hdr(skb))) {
86 enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb); 86 enum ip_defrag_users user =
87 nf_ct_defrag_user(ops->hooknum, skb);
88
87 if (nf_ct_ipv4_gather_frags(skb, user)) 89 if (nf_ct_ipv4_gather_frags(skb, user))
88 return NF_STOLEN; 90 return NF_STOLEN;
89 } 91 }
diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c
new file mode 100644
index 000000000000..3e67ef1c676f
--- /dev/null
+++ b/net/ipv4/netfilter/nf_tables_arp.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright (c) 2008-2010 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/netfilter_arp.h>
15#include <net/netfilter/nf_tables.h>
16
17static struct nft_af_info nft_af_arp __read_mostly = {
18 .family = NFPROTO_ARP,
19 .nhooks = NF_ARP_NUMHOOKS,
20 .owner = THIS_MODULE,
21};
22
23static int nf_tables_arp_init_net(struct net *net)
24{
25 net->nft.arp = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
26 if (net->nft.arp== NULL)
27 return -ENOMEM;
28
29 memcpy(net->nft.arp, &nft_af_arp, sizeof(nft_af_arp));
30
31 if (nft_register_afinfo(net, net->nft.arp) < 0)
32 goto err;
33
34 return 0;
35err:
36 kfree(net->nft.arp);
37 return -ENOMEM;
38}
39
40static void nf_tables_arp_exit_net(struct net *net)
41{
42 nft_unregister_afinfo(net->nft.arp);
43 kfree(net->nft.arp);
44}
45
46static struct pernet_operations nf_tables_arp_net_ops = {
47 .init = nf_tables_arp_init_net,
48 .exit = nf_tables_arp_exit_net,
49};
50
51static unsigned int
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",
68 .type = NFT_CHAIN_T_DEFAULT,
69 .hook_mask = (1 << NF_ARP_IN) |
70 (1 << NF_ARP_OUT) |
71 (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};
78
79static int __init nf_tables_arp_init(void)
80{
81 int ret;
82
83 nft_register_chain_type(&filter_arp);
84 ret = register_pernet_subsys(&nf_tables_arp_net_ops);
85 if (ret < 0)
86 nft_unregister_chain_type(&filter_arp);
87
88 return ret;
89}
90
91static void __exit nf_tables_arp_exit(void)
92{
93 unregister_pernet_subsys(&nf_tables_arp_net_ops);
94 nft_unregister_chain_type(&filter_arp);
95}
96
97module_init(nf_tables_arp_init);
98module_exit(nf_tables_arp_exit);
99
100MODULE_LICENSE("GPL");
101MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
102MODULE_ALIAS_NFT_FAMILY(3); /* NFPROTO_ARP */
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c
new file mode 100644
index 000000000000..8f7536be1322
--- /dev/null
+++ b/net/ipv4/netfilter/nf_tables_ipv4.c
@@ -0,0 +1,128 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012-2013 Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/ip.h>
15#include <linux/netfilter_ipv4.h>
16#include <net/netfilter/nf_tables.h>
17#include <net/net_namespace.h>
18#include <net/ip.h>
19#include <net/net_namespace.h>
20#include <net/netfilter/nf_tables_ipv4.h>
21
22static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops,
23 struct sk_buff *skb,
24 const struct net_device *in,
25 const struct net_device *out,
26 int (*okfn)(struct sk_buff *))
27{
28 struct nft_pktinfo pkt;
29
30 if (unlikely(skb->len < sizeof(struct iphdr) ||
31 ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
32 if (net_ratelimit())
33 pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
34 "packet\n");
35 return NF_ACCEPT;
36 }
37 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
38
39 return nft_do_chain_pktinfo(&pkt, ops);
40}
41
42static struct nft_af_info nft_af_ipv4 __read_mostly = {
43 .family = NFPROTO_IPV4,
44 .nhooks = NF_INET_NUMHOOKS,
45 .owner = THIS_MODULE,
46 .hooks = {
47 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
48 },
49};
50
51static int nf_tables_ipv4_init_net(struct net *net)
52{
53 net->nft.ipv4 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
54 if (net->nft.ipv4 == NULL)
55 return -ENOMEM;
56
57 memcpy(net->nft.ipv4, &nft_af_ipv4, sizeof(nft_af_ipv4));
58
59 if (nft_register_afinfo(net, net->nft.ipv4) < 0)
60 goto err;
61
62 return 0;
63err:
64 kfree(net->nft.ipv4);
65 return -ENOMEM;
66}
67
68static void nf_tables_ipv4_exit_net(struct net *net)
69{
70 nft_unregister_afinfo(net->nft.ipv4);
71 kfree(net->nft.ipv4);
72}
73
74static struct pernet_operations nf_tables_ipv4_net_ops = {
75 .init = nf_tables_ipv4_init_net,
76 .exit = nf_tables_ipv4_exit_net,
77};
78
79static unsigned int
80nft_do_chain_ipv4(const struct nf_hook_ops *ops,
81 struct sk_buff *skb,
82 const struct net_device *in,
83 const struct net_device *out,
84 int (*okfn)(struct sk_buff *))
85{
86 struct nft_pktinfo pkt;
87
88 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
89
90 return nft_do_chain_pktinfo(&pkt, ops);
91}
92
93static struct nf_chain_type filter_ipv4 = {
94 .family = NFPROTO_IPV4,
95 .name = "filter",
96 .type = NFT_CHAIN_T_DEFAULT,
97 .hook_mask = (1 << NF_INET_LOCAL_IN) |
98 (1 << NF_INET_LOCAL_OUT) |
99 (1 << NF_INET_FORWARD) |
100 (1 << NF_INET_PRE_ROUTING) |
101 (1 << NF_INET_POST_ROUTING),
102 .fn = {
103 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
104 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
105 [NF_INET_FORWARD] = nft_do_chain_ipv4,
106 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
107 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
108 },
109};
110
111static int __init nf_tables_ipv4_init(void)
112{
113 nft_register_chain_type(&filter_ipv4);
114 return register_pernet_subsys(&nf_tables_ipv4_net_ops);
115}
116
117static void __exit nf_tables_ipv4_exit(void)
118{
119 unregister_pernet_subsys(&nf_tables_ipv4_net_ops);
120 nft_unregister_chain_type(&filter_ipv4);
121}
122
123module_init(nf_tables_ipv4_init);
124module_exit(nf_tables_ipv4_exit);
125
126MODULE_LICENSE("GPL");
127MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
128MODULE_ALIAS_NFT_FAMILY(AF_INET);
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
new file mode 100644
index 000000000000..cf2c792cd971
--- /dev/null
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4 * Copyright (c) 2012 Intel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Development of this code funded by Astaro AG (http://www.astaro.com/)
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/list.h>
16#include <linux/skbuff.h>
17#include <linux/ip.h>
18#include <linux/netfilter.h>
19#include <linux/netfilter_ipv4.h>
20#include <linux/netfilter/nf_tables.h>
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_nat.h>
23#include <net/netfilter/nf_nat_core.h>
24#include <net/netfilter/nf_tables.h>
25#include <net/netfilter/nf_tables_ipv4.h>
26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/ip.h>
28
29/*
30 * NAT chains
31 */
32
33static unsigned int nf_nat_fn(const struct nf_hook_ops *ops,
34 struct sk_buff *skb,
35 const struct net_device *in,
36 const struct net_device *out,
37 int (*okfn)(struct sk_buff *))
38{
39 enum ip_conntrack_info ctinfo;
40 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
41 struct nf_conn_nat *nat;
42 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
43 struct nft_pktinfo pkt;
44 unsigned int ret;
45
46 if (ct == NULL || nf_ct_is_untracked(ct))
47 return NF_ACCEPT;
48
49 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
50
51 nat = nfct_nat(ct);
52 if (nat == NULL) {
53 /* Conntrack module was loaded late, can't add extension. */
54 if (nf_ct_is_confirmed(ct))
55 return NF_ACCEPT;
56 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
57 if (nat == NULL)
58 return NF_ACCEPT;
59 }
60
61 switch (ctinfo) {
62 case IP_CT_RELATED:
63 case IP_CT_RELATED + IP_CT_IS_REPLY:
64 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
65 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
66 ops->hooknum))
67 return NF_DROP;
68 else
69 return NF_ACCEPT;
70 }
71 /* Fall through */
72 case IP_CT_NEW:
73 if (nf_nat_initialized(ct, maniptype))
74 break;
75
76 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
77
78 ret = nft_do_chain_pktinfo(&pkt, ops);
79 if (ret != NF_ACCEPT)
80 return ret;
81 if (!nf_nat_initialized(ct, maniptype)) {
82 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
83 if (ret != NF_ACCEPT)
84 return ret;
85 }
86 default:
87 break;
88 }
89
90 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
91}
92
93static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops,
94 struct sk_buff *skb,
95 const struct net_device *in,
96 const struct net_device *out,
97 int (*okfn)(struct sk_buff *))
98{
99 __be32 daddr = ip_hdr(skb)->daddr;
100 unsigned int ret;
101
102 ret = nf_nat_fn(ops, skb, in, out, okfn);
103 if (ret != NF_DROP && ret != NF_STOLEN &&
104 ip_hdr(skb)->daddr != daddr) {
105 skb_dst_drop(skb);
106 }
107 return ret;
108}
109
110static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops,
111 struct sk_buff *skb,
112 const struct net_device *in,
113 const struct net_device *out,
114 int (*okfn)(struct sk_buff *))
115{
116 enum ip_conntrack_info ctinfo __maybe_unused;
117 const struct nf_conn *ct __maybe_unused;
118 unsigned int ret;
119
120 ret = nf_nat_fn(ops, skb, in, out, okfn);
121#ifdef CONFIG_XFRM
122 if (ret != NF_DROP && ret != NF_STOLEN &&
123 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
124 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
125
126 if (ct->tuplehash[dir].tuple.src.u3.ip !=
127 ct->tuplehash[!dir].tuple.dst.u3.ip ||
128 ct->tuplehash[dir].tuple.src.u.all !=
129 ct->tuplehash[!dir].tuple.dst.u.all)
130 return nf_xfrm_me_harder(skb, AF_INET) == 0 ?
131 ret : NF_DROP;
132 }
133#endif
134 return ret;
135}
136
137static unsigned int nf_nat_output(const struct nf_hook_ops *ops,
138 struct sk_buff *skb,
139 const struct net_device *in,
140 const struct net_device *out,
141 int (*okfn)(struct sk_buff *))
142{
143 enum ip_conntrack_info ctinfo;
144 const struct nf_conn *ct;
145 unsigned int ret;
146
147 ret = nf_nat_fn(ops, skb, in, out, okfn);
148 if (ret != NF_DROP && ret != NF_STOLEN &&
149 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
150 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
151
152 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
153 ct->tuplehash[!dir].tuple.src.u3.ip) {
154 if (ip_route_me_harder(skb, RTN_UNSPEC))
155 ret = NF_DROP;
156 }
157#ifdef CONFIG_XFRM
158 else if (ct->tuplehash[dir].tuple.dst.u.all !=
159 ct->tuplehash[!dir].tuple.src.u.all)
160 if (nf_xfrm_me_harder(skb, AF_INET))
161 ret = NF_DROP;
162#endif
163 }
164 return ret;
165}
166
167static struct nf_chain_type nft_chain_nat_ipv4 = {
168 .family = NFPROTO_IPV4,
169 .name = "nat",
170 .type = NFT_CHAIN_T_NAT,
171 .hook_mask = (1 << NF_INET_PRE_ROUTING) |
172 (1 << NF_INET_POST_ROUTING) |
173 (1 << NF_INET_LOCAL_OUT) |
174 (1 << NF_INET_LOCAL_IN),
175 .fn = {
176 [NF_INET_PRE_ROUTING] = nf_nat_prerouting,
177 [NF_INET_POST_ROUTING] = nf_nat_postrouting,
178 [NF_INET_LOCAL_OUT] = nf_nat_output,
179 [NF_INET_LOCAL_IN] = nf_nat_fn,
180 },
181 .me = THIS_MODULE,
182};
183
184static int __init nft_chain_nat_init(void)
185{
186 int err;
187
188 err = nft_register_chain_type(&nft_chain_nat_ipv4);
189 if (err < 0)
190 return err;
191
192 return 0;
193}
194
195static void __exit nft_chain_nat_exit(void)
196{
197 nft_unregister_chain_type(&nft_chain_nat_ipv4);
198}
199
200module_init(nft_chain_nat_init);
201module_exit(nft_chain_nat_exit);
202
203MODULE_LICENSE("GPL");
204MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
205MODULE_ALIAS_NFT_CHAIN(AF_INET, "nat");
diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c
new file mode 100644
index 000000000000..4e6bf9a3d7aa
--- /dev/null
+++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/list.h>
13#include <linux/skbuff.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter_ipv4.h>
17#include <linux/netfilter/nfnetlink.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20#include <net/netfilter/nf_tables_ipv4.h>
21#include <net/route.h>
22#include <net/ip.h>
23
24static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
25 struct sk_buff *skb,
26 const struct net_device *in,
27 const struct net_device *out,
28 int (*okfn)(struct sk_buff *))
29{
30 unsigned int ret;
31 struct nft_pktinfo pkt;
32 u32 mark;
33 __be32 saddr, daddr;
34 u_int8_t tos;
35 const struct iphdr *iph;
36
37 /* root is playing with raw sockets. */
38 if (skb->len < sizeof(struct iphdr) ||
39 ip_hdrlen(skb) < sizeof(struct iphdr))
40 return NF_ACCEPT;
41
42 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
43
44 mark = skb->mark;
45 iph = ip_hdr(skb);
46 saddr = iph->saddr;
47 daddr = iph->daddr;
48 tos = iph->tos;
49
50 ret = nft_do_chain_pktinfo(&pkt, ops);
51 if (ret != NF_DROP && ret != NF_QUEUE) {
52 iph = ip_hdr(skb);
53
54 if (iph->saddr != saddr ||
55 iph->daddr != daddr ||
56 skb->mark != mark ||
57 iph->tos != tos)
58 if (ip_route_me_harder(skb, RTN_UNSPEC))
59 ret = NF_DROP;
60 }
61 return ret;
62}
63
64static struct nf_chain_type nft_chain_route_ipv4 = {
65 .family = NFPROTO_IPV4,
66 .name = "route",
67 .type = NFT_CHAIN_T_ROUTE,
68 .hook_mask = (1 << NF_INET_LOCAL_OUT),
69 .fn = {
70 [NF_INET_LOCAL_OUT] = nf_route_table_hook,
71 },
72 .me = THIS_MODULE,
73};
74
75static int __init nft_chain_route_init(void)
76{
77 return nft_register_chain_type(&nft_chain_route_ipv4);
78}
79
80static void __exit nft_chain_route_exit(void)
81{
82 nft_unregister_chain_type(&nft_chain_route_ipv4);
83}
84
85module_init(nft_chain_route_init);
86module_exit(nft_chain_route_exit);
87
88MODULE_LICENSE("GPL");
89MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
90MODULE_ALIAS_NFT_CHAIN(AF_INET, "route");
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c
new file mode 100644
index 000000000000..fff5ba1a33b7
--- /dev/null
+++ b/net/ipv4/netfilter/nft_reject_ipv4.c
@@ -0,0 +1,123 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18#include <net/icmp.h>
19
20struct nft_reject {
21 enum nft_reject_types type:8;
22 u8 icmp_code;
23};
24
25static void nft_reject_eval(const struct nft_expr *expr,
26 struct nft_data data[NFT_REG_MAX + 1],
27 const struct nft_pktinfo *pkt)
28{
29 struct nft_reject *priv = nft_expr_priv(expr);
30
31 switch (priv->type) {
32 case NFT_REJECT_ICMP_UNREACH:
33 icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0);
34 break;
35 case NFT_REJECT_TCP_RST:
36 break;
37 }
38
39 data[NFT_REG_VERDICT].verdict = NF_DROP;
40}
41
42static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
43 [NFTA_REJECT_TYPE] = { .type = NLA_U32 },
44 [NFTA_REJECT_ICMP_CODE] = { .type = NLA_U8 },
45};
46
47static int nft_reject_init(const struct nft_ctx *ctx,
48 const struct nft_expr *expr,
49 const struct nlattr * const tb[])
50{
51 struct nft_reject *priv = nft_expr_priv(expr);
52
53 if (tb[NFTA_REJECT_TYPE] == NULL)
54 return -EINVAL;
55
56 priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
57 switch (priv->type) {
58 case NFT_REJECT_ICMP_UNREACH:
59 if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
60 return -EINVAL;
61 priv->icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
62 case NFT_REJECT_TCP_RST:
63 break;
64 default:
65 return -EINVAL;
66 }
67
68 return 0;
69}
70
71static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
72{
73 const struct nft_reject *priv = nft_expr_priv(expr);
74
75 if (nla_put_be32(skb, NFTA_REJECT_TYPE, priv->type))
76 goto nla_put_failure;
77
78 switch (priv->type) {
79 case NFT_REJECT_ICMP_UNREACH:
80 if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
81 goto nla_put_failure;
82 break;
83 }
84
85 return 0;
86
87nla_put_failure:
88 return -1;
89}
90
91static struct nft_expr_type nft_reject_type;
92static const struct nft_expr_ops nft_reject_ops = {
93 .type = &nft_reject_type,
94 .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
95 .eval = nft_reject_eval,
96 .init = nft_reject_init,
97 .dump = nft_reject_dump,
98};
99
100static struct nft_expr_type nft_reject_type __read_mostly = {
101 .name = "reject",
102 .ops = &nft_reject_ops,
103 .policy = nft_reject_policy,
104 .maxattr = NFTA_REJECT_MAX,
105 .owner = THIS_MODULE,
106};
107
108static int __init nft_reject_module_init(void)
109{
110 return nft_register_expr(&nft_reject_type);
111}
112
113static void __exit nft_reject_module_exit(void)
114{
115 nft_unregister_expr(&nft_reject_type);
116}
117
118module_init(nft_reject_module_init);
119module_exit(nft_reject_module_exit);
120
121MODULE_LICENSE("GPL");
122MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
123MODULE_ALIAS_NFT_EXPR("reject");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index a7f842b29b67..7702f9e90a04 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -25,6 +25,19 @@ config NF_CONNTRACK_IPV6
25 25
26 To compile it as a module, choose M here. If unsure, say N. 26 To compile it as a module, choose M here. If unsure, say N.
27 27
28config NF_TABLES_IPV6
29 depends on NF_TABLES
30 tristate "IPv6 nf_tables support"
31
32config NFT_CHAIN_ROUTE_IPV6
33 depends on NF_TABLES_IPV6
34 tristate "IPv6 nf_tables route chain support"
35
36config NFT_CHAIN_NAT_IPV6
37 depends on NF_TABLES_IPV6
38 depends on NF_NAT_IPV6 && NFT_NAT
39 tristate "IPv6 nf_tables nat chain support"
40
28config IP6_NF_IPTABLES 41config IP6_NF_IPTABLES
29 tristate "IP6 tables support (required for filtering)" 42 tristate "IP6 tables support (required for filtering)"
30 depends on INET && IPV6 43 depends on INET && IPV6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 2b53738f798c..d1b4928f34f7 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -23,6 +23,11 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
24obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o 24obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
25 25
26# nf_tables
27obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
28obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
29obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
30
26# matches 31# matches
27obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o 32obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
28obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o 33obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index 2748b042da72..bf9f612c1bc2 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -312,7 +312,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
312 return XT_CONTINUE; 312 return XT_CONTINUE;
313} 313}
314 314
315static unsigned int ipv6_synproxy_hook(unsigned int hooknum, 315static unsigned int ipv6_synproxy_hook(const struct nf_hook_ops *ops,
316 struct sk_buff *skb, 316 struct sk_buff *skb,
317 const struct net_device *in, 317 const struct net_device *in,
318 const struct net_device *out, 318 const struct net_device *out,
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 29b44b14c5ea..ca7f6c128086 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -32,13 +32,14 @@ static const struct xt_table packet_filter = {
32 32
33/* The work comes in here from netfilter.c. */ 33/* The work comes in here from netfilter.c. */
34static unsigned int 34static unsigned int
35ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, 35ip6table_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
36 const struct net_device *in, const struct net_device *out, 36 const struct net_device *in, const struct net_device *out,
37 int (*okfn)(struct sk_buff *)) 37 int (*okfn)(struct sk_buff *))
38{ 38{
39 const struct net *net = dev_net((in != NULL) ? in : out); 39 const struct net *net = dev_net((in != NULL) ? in : out);
40 40
41 return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); 41 return ip6t_do_table(skb, ops->hooknum, in, out,
42 net->ipv6.ip6table_filter);
42} 43}
43 44
44static struct nf_hook_ops *filter_ops __read_mostly; 45static struct nf_hook_ops *filter_ops __read_mostly;
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index c705907ae6ab..307bbb782d14 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -76,17 +76,17 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
76 76
77/* The work comes in here from netfilter.c. */ 77/* The work comes in here from netfilter.c. */
78static unsigned int 78static unsigned int
79ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, 79ip6table_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
80 const struct net_device *in, const struct net_device *out, 80 const struct net_device *in, const struct net_device *out,
81 int (*okfn)(struct sk_buff *)) 81 int (*okfn)(struct sk_buff *))
82{ 82{
83 if (hook == NF_INET_LOCAL_OUT) 83 if (ops->hooknum == NF_INET_LOCAL_OUT)
84 return ip6t_mangle_out(skb, out); 84 return ip6t_mangle_out(skb, out);
85 if (hook == NF_INET_POST_ROUTING) 85 if (ops->hooknum == NF_INET_POST_ROUTING)
86 return ip6t_do_table(skb, hook, in, out, 86 return ip6t_do_table(skb, ops->hooknum, in, out,
87 dev_net(out)->ipv6.ip6table_mangle); 87 dev_net(out)->ipv6.ip6table_mangle);
88 /* INPUT/FORWARD */ 88 /* INPUT/FORWARD */
89 return ip6t_do_table(skb, hook, in, out, 89 return ip6t_do_table(skb, ops->hooknum, in, out,
90 dev_net(in)->ipv6.ip6table_mangle); 90 dev_net(in)->ipv6.ip6table_mangle);
91} 91}
92 92
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 9b076d2d3a7b..84c7f33d0cf8 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -63,7 +63,7 @@ static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
63} 63}
64 64
65static unsigned int 65static unsigned int
66nf_nat_ipv6_fn(unsigned int hooknum, 66nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
67 struct sk_buff *skb, 67 struct sk_buff *skb,
68 const struct net_device *in, 68 const struct net_device *in,
69 const struct net_device *out, 69 const struct net_device *out,
@@ -72,7 +72,7 @@ nf_nat_ipv6_fn(unsigned int hooknum,
72 struct nf_conn *ct; 72 struct nf_conn *ct;
73 enum ip_conntrack_info ctinfo; 73 enum ip_conntrack_info ctinfo;
74 struct nf_conn_nat *nat; 74 struct nf_conn_nat *nat;
75 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 75 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
76 __be16 frag_off; 76 __be16 frag_off;
77 int hdrlen; 77 int hdrlen;
78 u8 nexthdr; 78 u8 nexthdr;
@@ -111,7 +111,8 @@ nf_nat_ipv6_fn(unsigned int hooknum,
111 111
112 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 112 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
113 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, 113 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
114 hooknum, hdrlen)) 114 ops->hooknum,
115 hdrlen))
115 return NF_DROP; 116 return NF_DROP;
116 else 117 else
117 return NF_ACCEPT; 118 return NF_ACCEPT;
@@ -124,14 +125,14 @@ nf_nat_ipv6_fn(unsigned int hooknum,
124 if (!nf_nat_initialized(ct, maniptype)) { 125 if (!nf_nat_initialized(ct, maniptype)) {
125 unsigned int ret; 126 unsigned int ret;
126 127
127 ret = nf_nat_rule_find(skb, hooknum, in, out, ct); 128 ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct);
128 if (ret != NF_ACCEPT) 129 if (ret != NF_ACCEPT)
129 return ret; 130 return ret;
130 } else { 131 } else {
131 pr_debug("Already setup manip %s for ct %p\n", 132 pr_debug("Already setup manip %s for ct %p\n",
132 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 133 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
133 ct); 134 ct);
134 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) 135 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
135 goto oif_changed; 136 goto oif_changed;
136 } 137 }
137 break; 138 break;
@@ -140,11 +141,11 @@ nf_nat_ipv6_fn(unsigned int hooknum,
140 /* ESTABLISHED */ 141 /* ESTABLISHED */
141 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 142 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
142 ctinfo == IP_CT_ESTABLISHED_REPLY); 143 ctinfo == IP_CT_ESTABLISHED_REPLY);
143 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) 144 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
144 goto oif_changed; 145 goto oif_changed;
145 } 146 }
146 147
147 return nf_nat_packet(ct, ctinfo, hooknum, skb); 148 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
148 149
149oif_changed: 150oif_changed:
150 nf_ct_kill_acct(ct, ctinfo, skb); 151 nf_ct_kill_acct(ct, ctinfo, skb);
@@ -152,7 +153,7 @@ oif_changed:
152} 153}
153 154
154static unsigned int 155static unsigned int
155nf_nat_ipv6_in(unsigned int hooknum, 156nf_nat_ipv6_in(const struct nf_hook_ops *ops,
156 struct sk_buff *skb, 157 struct sk_buff *skb,
157 const struct net_device *in, 158 const struct net_device *in,
158 const struct net_device *out, 159 const struct net_device *out,
@@ -161,7 +162,7 @@ nf_nat_ipv6_in(unsigned int hooknum,
161 unsigned int ret; 162 unsigned int ret;
162 struct in6_addr daddr = ipv6_hdr(skb)->daddr; 163 struct in6_addr daddr = ipv6_hdr(skb)->daddr;
163 164
164 ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); 165 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
165 if (ret != NF_DROP && ret != NF_STOLEN && 166 if (ret != NF_DROP && ret != NF_STOLEN &&
166 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) 167 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
167 skb_dst_drop(skb); 168 skb_dst_drop(skb);
@@ -170,7 +171,7 @@ nf_nat_ipv6_in(unsigned int hooknum,
170} 171}
171 172
172static unsigned int 173static unsigned int
173nf_nat_ipv6_out(unsigned int hooknum, 174nf_nat_ipv6_out(const struct nf_hook_ops *ops,
174 struct sk_buff *skb, 175 struct sk_buff *skb,
175 const struct net_device *in, 176 const struct net_device *in,
176 const struct net_device *out, 177 const struct net_device *out,
@@ -187,7 +188,7 @@ nf_nat_ipv6_out(unsigned int hooknum,
187 if (skb->len < sizeof(struct ipv6hdr)) 188 if (skb->len < sizeof(struct ipv6hdr))
188 return NF_ACCEPT; 189 return NF_ACCEPT;
189 190
190 ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); 191 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
191#ifdef CONFIG_XFRM 192#ifdef CONFIG_XFRM
192 if (ret != NF_DROP && ret != NF_STOLEN && 193 if (ret != NF_DROP && ret != NF_STOLEN &&
193 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 194 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
@@ -209,7 +210,7 @@ nf_nat_ipv6_out(unsigned int hooknum,
209} 210}
210 211
211static unsigned int 212static unsigned int
212nf_nat_ipv6_local_fn(unsigned int hooknum, 213nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops,
213 struct sk_buff *skb, 214 struct sk_buff *skb,
214 const struct net_device *in, 215 const struct net_device *in,
215 const struct net_device *out, 216 const struct net_device *out,
@@ -224,7 +225,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
224 if (skb->len < sizeof(struct ipv6hdr)) 225 if (skb->len < sizeof(struct ipv6hdr))
225 return NF_ACCEPT; 226 return NF_ACCEPT;
226 227
227 ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); 228 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
228 if (ret != NF_DROP && ret != NF_STOLEN && 229 if (ret != NF_DROP && ret != NF_STOLEN &&
229 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 230 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
230 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 231 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 9a626d86720f..5274740acecc 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -19,13 +19,14 @@ static const struct xt_table packet_raw = {
19 19
20/* The work comes in here from netfilter.c. */ 20/* The work comes in here from netfilter.c. */
21static unsigned int 21static unsigned int
22ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, 22ip6table_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
23 const struct net_device *in, const struct net_device *out, 23 const struct net_device *in, const struct net_device *out,
24 int (*okfn)(struct sk_buff *)) 24 int (*okfn)(struct sk_buff *))
25{ 25{
26 const struct net *net = dev_net((in != NULL) ? in : out); 26 const struct net *net = dev_net((in != NULL) ? in : out);
27 27
28 return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); 28 return ip6t_do_table(skb, ops->hooknum, in, out,
29 net->ipv6.ip6table_raw);
29} 30}
30 31
31static struct nf_hook_ops *rawtable_ops __read_mostly; 32static struct nf_hook_ops *rawtable_ops __read_mostly;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index ce88d1d7e525..ab3b0219ecfa 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -36,14 +36,15 @@ static const struct xt_table security_table = {
36}; 36};
37 37
38static unsigned int 38static unsigned int
39ip6table_security_hook(unsigned int hook, struct sk_buff *skb, 39ip6table_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
40 const struct net_device *in, 40 const struct net_device *in,
41 const struct net_device *out, 41 const struct net_device *out,
42 int (*okfn)(struct sk_buff *)) 42 int (*okfn)(struct sk_buff *))
43{ 43{
44 const struct net *net = dev_net((in != NULL) ? in : out); 44 const struct net *net = dev_net((in != NULL) ? in : out);
45 45
46 return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); 46 return ip6t_do_table(skb, ops->hooknum, in, out,
47 net->ipv6.ip6table_security);
47} 48}
48 49
49static struct nf_hook_ops *sectbl_ops __read_mostly; 50static struct nf_hook_ops *sectbl_ops __read_mostly;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 54b75ead5a69..486545eb42ce 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -95,7 +95,7 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
95 return NF_ACCEPT; 95 return NF_ACCEPT;
96} 96}
97 97
98static unsigned int ipv6_helper(unsigned int hooknum, 98static unsigned int ipv6_helper(const struct nf_hook_ops *ops,
99 struct sk_buff *skb, 99 struct sk_buff *skb,
100 const struct net_device *in, 100 const struct net_device *in,
101 const struct net_device *out, 101 const struct net_device *out,
@@ -133,7 +133,7 @@ static unsigned int ipv6_helper(unsigned int hooknum,
133 return helper->help(skb, protoff, ct, ctinfo); 133 return helper->help(skb, protoff, ct, ctinfo);
134} 134}
135 135
136static unsigned int ipv6_confirm(unsigned int hooknum, 136static unsigned int ipv6_confirm(const struct nf_hook_ops *ops,
137 struct sk_buff *skb, 137 struct sk_buff *skb,
138 const struct net_device *in, 138 const struct net_device *in,
139 const struct net_device *out, 139 const struct net_device *out,
@@ -219,16 +219,17 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
219 return nf_conntrack_in(net, PF_INET6, hooknum, skb); 219 return nf_conntrack_in(net, PF_INET6, hooknum, skb);
220} 220}
221 221
222static unsigned int ipv6_conntrack_in(unsigned int hooknum, 222static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops,
223 struct sk_buff *skb, 223 struct sk_buff *skb,
224 const struct net_device *in, 224 const struct net_device *in,
225 const struct net_device *out, 225 const struct net_device *out,
226 int (*okfn)(struct sk_buff *)) 226 int (*okfn)(struct sk_buff *))
227{ 227{
228 return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn); 228 return __ipv6_conntrack_in(dev_net(in), ops->hooknum, skb, in, out,
229 okfn);
229} 230}
230 231
231static unsigned int ipv6_conntrack_local(unsigned int hooknum, 232static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops,
232 struct sk_buff *skb, 233 struct sk_buff *skb,
233 const struct net_device *in, 234 const struct net_device *in,
234 const struct net_device *out, 235 const struct net_device *out,
@@ -239,7 +240,8 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
239 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); 240 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
240 return NF_ACCEPT; 241 return NF_ACCEPT;
241 } 242 }
242 return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn); 243 return __ipv6_conntrack_in(dev_net(out), ops->hooknum, skb, in, out,
244 okfn);
243} 245}
244 246
245static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { 247static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index aacd121fe8c5..ec483aa3f60f 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -52,7 +52,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
52 52
53} 53}
54 54
55static unsigned int ipv6_defrag(unsigned int hooknum, 55static unsigned int ipv6_defrag(const struct nf_hook_ops *ops,
56 struct sk_buff *skb, 56 struct sk_buff *skb,
57 const struct net_device *in, 57 const struct net_device *in,
58 const struct net_device *out, 58 const struct net_device *out,
@@ -66,7 +66,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
66 return NF_ACCEPT; 66 return NF_ACCEPT;
67#endif 67#endif
68 68
69 reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); 69 reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(ops->hooknum, skb));
70 /* queued */ 70 /* queued */
71 if (reasm == NULL) 71 if (reasm == NULL)
72 return NF_STOLEN; 72 return NF_STOLEN;
@@ -75,7 +75,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
75 if (reasm == skb) 75 if (reasm == skb)
76 return NF_ACCEPT; 76 return NF_ACCEPT;
77 77
78 nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, 78 nf_ct_frag6_output(ops->hooknum, reasm, (struct net_device *)in,
79 (struct net_device *)out, okfn); 79 (struct net_device *)out, okfn);
80 80
81 return NF_STOLEN; 81 return NF_STOLEN;
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c
new file mode 100644
index 000000000000..d77db8a13505
--- /dev/null
+++ b/net/ipv6/netfilter/nf_tables_ipv6.c
@@ -0,0 +1,127 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012-2013 Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/ipv6.h>
15#include <linux/netfilter_ipv6.h>
16#include <net/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_ipv6.h>
18
19static unsigned int nft_ipv6_output(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 if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
28 if (net_ratelimit())
29 pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
30 "packet\n");
31 return NF_ACCEPT;
32 }
33 if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
34 return NF_DROP;
35
36 return nft_do_chain_pktinfo(&pkt, ops);
37}
38
39static struct nft_af_info nft_af_ipv6 __read_mostly = {
40 .family = NFPROTO_IPV6,
41 .nhooks = NF_INET_NUMHOOKS,
42 .owner = THIS_MODULE,
43 .hooks = {
44 [NF_INET_LOCAL_OUT] = nft_ipv6_output,
45 },
46};
47
48static int nf_tables_ipv6_init_net(struct net *net)
49{
50 net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
51 if (net->nft.ipv6 == NULL)
52 return -ENOMEM;
53
54 memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6));
55
56 if (nft_register_afinfo(net, net->nft.ipv6) < 0)
57 goto err;
58
59 return 0;
60err:
61 kfree(net->nft.ipv6);
62 return -ENOMEM;
63}
64
65static void nf_tables_ipv6_exit_net(struct net *net)
66{
67 nft_unregister_afinfo(net->nft.ipv6);
68 kfree(net->nft.ipv6);
69}
70
71static struct pernet_operations nf_tables_ipv6_net_ops = {
72 .init = nf_tables_ipv6_init_net,
73 .exit = nf_tables_ipv6_exit_net,
74};
75
76static unsigned int
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",
95 .type = NFT_CHAIN_T_DEFAULT,
96 .hook_mask = (1 << NF_INET_LOCAL_IN) |
97 (1 << NF_INET_LOCAL_OUT) |
98 (1 << NF_INET_FORWARD) |
99 (1 << NF_INET_PRE_ROUTING) |
100 (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};
109
110static int __init nf_tables_ipv6_init(void)
111{
112 nft_register_chain_type(&filter_ipv6);
113 return register_pernet_subsys(&nf_tables_ipv6_net_ops);
114}
115
116static void __exit nf_tables_ipv6_exit(void)
117{
118 unregister_pernet_subsys(&nf_tables_ipv6_net_ops);
119 nft_unregister_chain_type(&filter_ipv6);
120}
121
122module_init(nf_tables_ipv6_init);
123module_exit(nf_tables_ipv6_exit);
124
125MODULE_LICENSE("GPL");
126MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
127MODULE_ALIAS_NFT_FAMILY(AF_INET6);
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
new file mode 100644
index 000000000000..e86dcd70dc76
--- /dev/null
+++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
@@ -0,0 +1,211 @@
1/*
2 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012 Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/ip.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv6.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_conntrack.h>
20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_core.h>
22#include <net/netfilter/nf_tables.h>
23#include <net/netfilter/nf_tables_ipv6.h>
24#include <net/netfilter/nf_nat_l3proto.h>
25#include <net/ipv6.h>
26
27/*
28 * IPv6 NAT chains
29 */
30
31static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
32 struct sk_buff *skb,
33 const struct net_device *in,
34 const struct net_device *out,
35 int (*okfn)(struct sk_buff *))
36{
37 enum ip_conntrack_info ctinfo;
38 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
39 struct nf_conn_nat *nat;
40 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
41 __be16 frag_off;
42 int hdrlen;
43 u8 nexthdr;
44 struct nft_pktinfo pkt;
45 unsigned int ret;
46
47 if (ct == NULL || nf_ct_is_untracked(ct))
48 return NF_ACCEPT;
49
50 nat = nfct_nat(ct);
51 if (nat == NULL) {
52 /* Conntrack module was loaded late, can't add extension. */
53 if (nf_ct_is_confirmed(ct))
54 return NF_ACCEPT;
55 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
56 if (nat == NULL)
57 return NF_ACCEPT;
58 }
59
60 switch (ctinfo) {
61 case IP_CT_RELATED:
62 case IP_CT_RELATED + IP_CT_IS_REPLY:
63 nexthdr = ipv6_hdr(skb)->nexthdr;
64 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
65 &nexthdr, &frag_off);
66
67 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
68 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
69 ops->hooknum,
70 hdrlen))
71 return NF_DROP;
72 else
73 return NF_ACCEPT;
74 }
75 /* Fall through */
76 case IP_CT_NEW:
77 if (nf_nat_initialized(ct, maniptype))
78 break;
79
80 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
81
82 ret = nft_do_chain_pktinfo(&pkt, ops);
83 if (ret != NF_ACCEPT)
84 return ret;
85 if (!nf_nat_initialized(ct, maniptype)) {
86 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
87 if (ret != NF_ACCEPT)
88 return ret;
89 }
90 default:
91 break;
92 }
93
94 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
95}
96
97static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops,
98 struct sk_buff *skb,
99 const struct net_device *in,
100 const struct net_device *out,
101 int (*okfn)(struct sk_buff *))
102{
103 struct in6_addr daddr = ipv6_hdr(skb)->daddr;
104 unsigned int ret;
105
106 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
107 if (ret != NF_DROP && ret != NF_STOLEN &&
108 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
109 skb_dst_drop(skb);
110
111 return ret;
112}
113
114static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops,
115 struct sk_buff *skb,
116 const struct net_device *in,
117 const struct net_device *out,
118 int (*okfn)(struct sk_buff *))
119{
120 enum ip_conntrack_info ctinfo __maybe_unused;
121 const struct nf_conn *ct __maybe_unused;
122 unsigned int ret;
123
124 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
125#ifdef CONFIG_XFRM
126 if (ret != NF_DROP && ret != NF_STOLEN &&
127 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
128 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
129 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
130
131 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
132 &ct->tuplehash[!dir].tuple.dst.u3) ||
133 (ct->tuplehash[dir].tuple.src.u.all !=
134 ct->tuplehash[!dir].tuple.dst.u.all))
135 if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
136 ret = NF_DROP;
137 }
138#endif
139 return ret;
140}
141
142static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops,
143 struct sk_buff *skb,
144 const struct net_device *in,
145 const struct net_device *out,
146 int (*okfn)(struct sk_buff *))
147{
148 enum ip_conntrack_info ctinfo;
149 const struct nf_conn *ct;
150 unsigned int ret;
151
152 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
153 if (ret != NF_DROP && ret != NF_STOLEN &&
154 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
155 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
156
157 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
158 &ct->tuplehash[!dir].tuple.src.u3)) {
159 if (ip6_route_me_harder(skb))
160 ret = NF_DROP;
161 }
162#ifdef CONFIG_XFRM
163 else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
164 ct->tuplehash[dir].tuple.dst.u.all !=
165 ct->tuplehash[!dir].tuple.src.u.all)
166 if (nf_xfrm_me_harder(skb, AF_INET6))
167 ret = NF_DROP;
168#endif
169 }
170 return ret;
171}
172
173static struct nf_chain_type nft_chain_nat_ipv6 = {
174 .family = NFPROTO_IPV6,
175 .name = "nat",
176 .type = NFT_CHAIN_T_NAT,
177 .hook_mask = (1 << NF_INET_PRE_ROUTING) |
178 (1 << NF_INET_POST_ROUTING) |
179 (1 << NF_INET_LOCAL_OUT) |
180 (1 << NF_INET_LOCAL_IN),
181 .fn = {
182 [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting,
183 [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting,
184 [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output,
185 [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn,
186 },
187 .me = THIS_MODULE,
188};
189
190static int __init nft_chain_nat_ipv6_init(void)
191{
192 int err;
193
194 err = nft_register_chain_type(&nft_chain_nat_ipv6);
195 if (err < 0)
196 return err;
197
198 return 0;
199}
200
201static void __exit nft_chain_nat_ipv6_exit(void)
202{
203 nft_unregister_chain_type(&nft_chain_nat_ipv6);
204}
205
206module_init(nft_chain_nat_ipv6_init);
207module_exit(nft_chain_nat_ipv6_exit);
208
209MODULE_LICENSE("GPL");
210MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
211MODULE_ALIAS_NFT_CHAIN(AF_INET6, "nat");
diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c
new file mode 100644
index 000000000000..3fe40f0456ad
--- /dev/null
+++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/list.h>
15#include <linux/skbuff.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter_ipv6.h>
19#include <linux/netfilter/nfnetlink.h>
20#include <linux/netfilter/nf_tables.h>
21#include <net/netfilter/nf_tables.h>
22#include <net/netfilter/nf_tables_ipv6.h>
23#include <net/route.h>
24
25static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
26 struct sk_buff *skb,
27 const struct net_device *in,
28 const struct net_device *out,
29 int (*okfn)(struct sk_buff *))
30{
31 unsigned int ret;
32 struct nft_pktinfo pkt;
33 struct in6_addr saddr, daddr;
34 u_int8_t hop_limit;
35 u32 mark, flowlabel;
36
37 /* malformed packet, drop it */
38 if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
39 return NF_DROP;
40
41 /* save source/dest address, mark, hoplimit, flowlabel, priority */
42 memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
43 memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
44 mark = skb->mark;
45 hop_limit = ipv6_hdr(skb)->hop_limit;
46
47 /* flowlabel and prio (includes version, which shouldn't change either */
48 flowlabel = *((u32 *)ipv6_hdr(skb));
49
50 ret = nft_do_chain_pktinfo(&pkt, ops);
51 if (ret != NF_DROP && ret != NF_QUEUE &&
52 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
53 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
54 skb->mark != mark ||
55 ipv6_hdr(skb)->hop_limit != hop_limit ||
56 flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
57 return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
58
59 return ret;
60}
61
62static struct nf_chain_type nft_chain_route_ipv6 = {
63 .family = NFPROTO_IPV6,
64 .name = "route",
65 .type = NFT_CHAIN_T_ROUTE,
66 .hook_mask = (1 << NF_INET_LOCAL_OUT),
67 .fn = {
68 [NF_INET_LOCAL_OUT] = nf_route_table_hook,
69 },
70 .me = THIS_MODULE,
71};
72
73static int __init nft_chain_route_init(void)
74{
75 return nft_register_chain_type(&nft_chain_route_ipv6);
76}
77
78static void __exit nft_chain_route_exit(void)
79{
80 nft_unregister_chain_type(&nft_chain_route_ipv6);
81}
82
83module_init(nft_chain_route_init);
84module_exit(nft_chain_route_exit);
85
86MODULE_LICENSE("GPL");
87MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
88MODULE_ALIAS_NFT_CHAIN(AF_INET6, "route");
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 6e839b6dff2b..48acec17e27a 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -413,6 +413,58 @@ config NETFILTER_SYNPROXY
413 413
414endif # NF_CONNTRACK 414endif # NF_CONNTRACK
415 415
416config NF_TABLES
417 depends on NETFILTER_NETLINK
418 tristate "Netfilter nf_tables support"
419
420config NFT_EXTHDR
421 depends on NF_TABLES
422 tristate "Netfilter nf_tables IPv6 exthdr module"
423
424config NFT_META
425 depends on NF_TABLES
426 tristate "Netfilter nf_tables meta module"
427
428config NFT_CT
429 depends on NF_TABLES
430 depends on NF_CONNTRACK
431 tristate "Netfilter nf_tables conntrack module"
432
433config NFT_RBTREE
434 depends on NF_TABLES
435 tristate "Netfilter nf_tables rbtree set module"
436
437config NFT_HASH
438 depends on NF_TABLES
439 tristate "Netfilter nf_tables hash set module"
440
441config NFT_COUNTER
442 depends on NF_TABLES
443 tristate "Netfilter nf_tables counter module"
444
445config NFT_LOG
446 depends on NF_TABLES
447 tristate "Netfilter nf_tables log module"
448
449config NFT_LIMIT
450 depends on NF_TABLES
451 tristate "Netfilter nf_tables limit module"
452
453config NFT_NAT
454 depends on NF_TABLES
455 depends on NF_CONNTRACK
456 depends on NF_NAT
457 tristate "Netfilter nf_tables nat module"
458
459config NFT_COMPAT
460 depends on NF_TABLES
461 depends on NETFILTER_XTABLES
462 tristate "Netfilter x_tables over nf_tables module"
463 help
464 This is required if you intend to use any of existing
465 x_tables match/target extensions over the nf_tables
466 framework.
467
416config NETFILTER_XTABLES 468config NETFILTER_XTABLES
417 tristate "Netfilter Xtables support (required for ip_tables)" 469 tristate "Netfilter Xtables support (required for ip_tables)"
418 default m if NETFILTER_ADVANCED=n 470 default m if NETFILTER_ADVANCED=n
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index c3a0a12907f6..394483b2c193 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -64,6 +64,24 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
64# SYNPROXY 64# SYNPROXY
65obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o 65obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
66 66
67# nf_tables
68nf_tables-objs += nf_tables_core.o nf_tables_api.o
69nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o
70nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
71
72obj-$(CONFIG_NF_TABLES) += nf_tables.o
73obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
74obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
75obj-$(CONFIG_NFT_META) += nft_meta.o
76obj-$(CONFIG_NFT_CT) += nft_ct.o
77obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
78obj-$(CONFIG_NFT_NAT) += nft_nat.o
79#nf_tables-objs += nft_meta_target.o
80obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o
81obj-$(CONFIG_NFT_HASH) += nft_hash.o
82obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
83obj-$(CONFIG_NFT_LOG) += nft_log.o
84
67# generic X tables 85# generic X tables
68obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o 86obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
69 87
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 593b16ea45e0..1fbab0cdd302 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -146,7 +146,7 @@ unsigned int nf_iterate(struct list_head *head,
146 /* Optimization: we don't need to hold module 146 /* Optimization: we don't need to hold module
147 reference here, since function can't sleep. --RR */ 147 reference here, since function can't sleep. --RR */
148repeat: 148repeat:
149 verdict = (*elemp)->hook(hook, skb, indev, outdev, okfn); 149 verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn);
150 if (verdict != NF_ACCEPT) { 150 if (verdict != NF_ACCEPT) {
151#ifdef CONFIG_NETFILTER_DEBUG 151#ifdef CONFIG_NETFILTER_DEBUG
152 if (unlikely((verdict & NF_VERDICT_MASK) 152 if (unlikely((verdict & NF_VERDICT_MASK)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 74fd00c27210..34fda62f40f6 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1239,11 +1239,11 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1239 * Check if packet is reply for established ip_vs_conn. 1239 * Check if packet is reply for established ip_vs_conn.
1240 */ 1240 */
1241static unsigned int 1241static unsigned int
1242ip_vs_reply4(unsigned int hooknum, struct sk_buff *skb, 1242ip_vs_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
1243 const struct net_device *in, const struct net_device *out, 1243 const struct net_device *in, const struct net_device *out,
1244 int (*okfn)(struct sk_buff *)) 1244 int (*okfn)(struct sk_buff *))
1245{ 1245{
1246 return ip_vs_out(hooknum, skb, AF_INET); 1246 return ip_vs_out(ops->hooknum, skb, AF_INET);
1247} 1247}
1248 1248
1249/* 1249/*
@@ -1251,11 +1251,11 @@ ip_vs_reply4(unsigned int hooknum, struct sk_buff *skb,
1251 * Check if packet is reply for established ip_vs_conn. 1251 * Check if packet is reply for established ip_vs_conn.
1252 */ 1252 */
1253static unsigned int 1253static unsigned int
1254ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb, 1254ip_vs_local_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
1255 const struct net_device *in, const struct net_device *out, 1255 const struct net_device *in, const struct net_device *out,
1256 int (*okfn)(struct sk_buff *)) 1256 int (*okfn)(struct sk_buff *))
1257{ 1257{
1258 return ip_vs_out(hooknum, skb, AF_INET); 1258 return ip_vs_out(ops->hooknum, skb, AF_INET);
1259} 1259}
1260 1260
1261#ifdef CONFIG_IP_VS_IPV6 1261#ifdef CONFIG_IP_VS_IPV6
@@ -1266,11 +1266,11 @@ ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb,
1266 * Check if packet is reply for established ip_vs_conn. 1266 * Check if packet is reply for established ip_vs_conn.
1267 */ 1267 */
1268static unsigned int 1268static unsigned int
1269ip_vs_reply6(unsigned int hooknum, struct sk_buff *skb, 1269ip_vs_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1270 const struct net_device *in, const struct net_device *out, 1270 const struct net_device *in, const struct net_device *out,
1271 int (*okfn)(struct sk_buff *)) 1271 int (*okfn)(struct sk_buff *))
1272{ 1272{
1273 return ip_vs_out(hooknum, skb, AF_INET6); 1273 return ip_vs_out(ops->hooknum, skb, AF_INET6);
1274} 1274}
1275 1275
1276/* 1276/*
@@ -1278,11 +1278,11 @@ ip_vs_reply6(unsigned int hooknum, struct sk_buff *skb,
1278 * Check if packet is reply for established ip_vs_conn. 1278 * Check if packet is reply for established ip_vs_conn.
1279 */ 1279 */
1280static unsigned int 1280static unsigned int
1281ip_vs_local_reply6(unsigned int hooknum, struct sk_buff *skb, 1281ip_vs_local_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1282 const struct net_device *in, const struct net_device *out, 1282 const struct net_device *in, const struct net_device *out,
1283 int (*okfn)(struct sk_buff *)) 1283 int (*okfn)(struct sk_buff *))
1284{ 1284{
1285 return ip_vs_out(hooknum, skb, AF_INET6); 1285 return ip_vs_out(ops->hooknum, skb, AF_INET6);
1286} 1286}
1287 1287
1288#endif 1288#endif
@@ -1733,12 +1733,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1733 * Schedule and forward packets from remote clients 1733 * Schedule and forward packets from remote clients
1734 */ 1734 */
1735static unsigned int 1735static unsigned int
1736ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb, 1736ip_vs_remote_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
1737 const struct net_device *in, 1737 const struct net_device *in,
1738 const struct net_device *out, 1738 const struct net_device *out,
1739 int (*okfn)(struct sk_buff *)) 1739 int (*okfn)(struct sk_buff *))
1740{ 1740{
1741 return ip_vs_in(hooknum, skb, AF_INET); 1741 return ip_vs_in(ops->hooknum, skb, AF_INET);
1742} 1742}
1743 1743
1744/* 1744/*
@@ -1746,11 +1746,11 @@ ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb,
1746 * Schedule and forward packets from local clients 1746 * Schedule and forward packets from local clients
1747 */ 1747 */
1748static unsigned int 1748static unsigned int
1749ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb, 1749ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
1750 const struct net_device *in, const struct net_device *out, 1750 const struct net_device *in, const struct net_device *out,
1751 int (*okfn)(struct sk_buff *)) 1751 int (*okfn)(struct sk_buff *))
1752{ 1752{
1753 return ip_vs_in(hooknum, skb, AF_INET); 1753 return ip_vs_in(ops->hooknum, skb, AF_INET);
1754} 1754}
1755 1755
1756#ifdef CONFIG_IP_VS_IPV6 1756#ifdef CONFIG_IP_VS_IPV6
@@ -1760,7 +1760,7 @@ ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
1760 * Copy info from first fragment, to the rest of them. 1760 * Copy info from first fragment, to the rest of them.
1761 */ 1761 */
1762static unsigned int 1762static unsigned int
1763ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb, 1763ip_vs_preroute_frag6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1764 const struct net_device *in, 1764 const struct net_device *in,
1765 const struct net_device *out, 1765 const struct net_device *out,
1766 int (*okfn)(struct sk_buff *)) 1766 int (*okfn)(struct sk_buff *))
@@ -1792,12 +1792,12 @@ ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb,
1792 * Schedule and forward packets from remote clients 1792 * Schedule and forward packets from remote clients
1793 */ 1793 */
1794static unsigned int 1794static unsigned int
1795ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb, 1795ip_vs_remote_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1796 const struct net_device *in, 1796 const struct net_device *in,
1797 const struct net_device *out, 1797 const struct net_device *out,
1798 int (*okfn)(struct sk_buff *)) 1798 int (*okfn)(struct sk_buff *))
1799{ 1799{
1800 return ip_vs_in(hooknum, skb, AF_INET6); 1800 return ip_vs_in(ops->hooknum, skb, AF_INET6);
1801} 1801}
1802 1802
1803/* 1803/*
@@ -1805,11 +1805,11 @@ ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb,
1805 * Schedule and forward packets from local clients 1805 * Schedule and forward packets from local clients
1806 */ 1806 */
1807static unsigned int 1807static unsigned int
1808ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb, 1808ip_vs_local_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1809 const struct net_device *in, const struct net_device *out, 1809 const struct net_device *in, const struct net_device *out,
1810 int (*okfn)(struct sk_buff *)) 1810 int (*okfn)(struct sk_buff *))
1811{ 1811{
1812 return ip_vs_in(hooknum, skb, AF_INET6); 1812 return ip_vs_in(ops->hooknum, skb, AF_INET6);
1813} 1813}
1814 1814
1815#endif 1815#endif
@@ -1825,7 +1825,7 @@ ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb,
1825 * and send them to ip_vs_in_icmp. 1825 * and send them to ip_vs_in_icmp.
1826 */ 1826 */
1827static unsigned int 1827static unsigned int
1828ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, 1828ip_vs_forward_icmp(const struct nf_hook_ops *ops, struct sk_buff *skb,
1829 const struct net_device *in, const struct net_device *out, 1829 const struct net_device *in, const struct net_device *out,
1830 int (*okfn)(struct sk_buff *)) 1830 int (*okfn)(struct sk_buff *))
1831{ 1831{
@@ -1842,12 +1842,12 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
1842 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) 1842 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
1843 return NF_ACCEPT; 1843 return NF_ACCEPT;
1844 1844
1845 return ip_vs_in_icmp(skb, &r, hooknum); 1845 return ip_vs_in_icmp(skb, &r, ops->hooknum);
1846} 1846}
1847 1847
1848#ifdef CONFIG_IP_VS_IPV6 1848#ifdef CONFIG_IP_VS_IPV6
1849static unsigned int 1849static unsigned int
1850ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, 1850ip_vs_forward_icmp_v6(const struct nf_hook_ops *ops, struct sk_buff *skb,
1851 const struct net_device *in, const struct net_device *out, 1851 const struct net_device *in, const struct net_device *out,
1852 int (*okfn)(struct sk_buff *)) 1852 int (*okfn)(struct sk_buff *))
1853{ 1853{
@@ -1866,7 +1866,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1866 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) 1866 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
1867 return NF_ACCEPT; 1867 return NF_ACCEPT;
1868 1868
1869 return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr); 1869 return ip_vs_in_icmp_v6(skb, &r, ops->hooknum, &iphdr);
1870} 1870}
1871#endif 1871#endif
1872 1872
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 6f0f4f7f68a5..63a815402211 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -432,6 +432,26 @@ nf_nat_setup_info(struct nf_conn *ct,
432} 432}
433EXPORT_SYMBOL(nf_nat_setup_info); 433EXPORT_SYMBOL(nf_nat_setup_info);
434 434
435unsigned int
436nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
437{
438 /* Force range to this IP; let proto decide mapping for
439 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
440 * Use reply in case it's already been mangled (eg local packet).
441 */
442 union nf_inet_addr ip =
443 (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
444 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
445 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
446 struct nf_nat_range range = {
447 .flags = NF_NAT_RANGE_MAP_IPS,
448 .min_addr = ip,
449 .max_addr = ip,
450 };
451 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
452}
453EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
454
435/* Do packet manipulations according to nf_nat_setup_info. */ 455/* Do packet manipulations according to nf_nat_setup_info. */
436unsigned int nf_nat_packet(struct nf_conn *ct, 456unsigned int nf_nat_packet(struct nf_conn *ct,
437 enum ip_conntrack_info ctinfo, 457 enum ip_conntrack_info ctinfo,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
new file mode 100644
index 000000000000..dcddc49c0e08
--- /dev/null
+++ b/net/netfilter/nf_tables_api.c
@@ -0,0 +1,3275 @@
1/*
2 * Copyright (c) 2007-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nfnetlink.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables_core.h>
20#include <net/netfilter/nf_tables.h>
21#include <net/net_namespace.h>
22#include <net/sock.h>
23
24static LIST_HEAD(nf_tables_expressions);
25
26/**
27 * nft_register_afinfo - register nf_tables address family info
28 *
29 * @afi: address family info to register
30 *
31 * Register the address family for use with nf_tables. Returns zero on
32 * success or a negative errno code otherwise.
33 */
34int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
35{
36 INIT_LIST_HEAD(&afi->tables);
37 nfnl_lock(NFNL_SUBSYS_NFTABLES);
38 list_add_tail(&afi->list, &net->nft.af_info);
39 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
40 return 0;
41}
42EXPORT_SYMBOL_GPL(nft_register_afinfo);
43
44/**
45 * nft_unregister_afinfo - unregister nf_tables address family info
46 *
47 * @afi: address family info to unregister
48 *
49 * Unregister the address family for use with nf_tables.
50 */
51void nft_unregister_afinfo(struct nft_af_info *afi)
52{
53 nfnl_lock(NFNL_SUBSYS_NFTABLES);
54 list_del(&afi->list);
55 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
56}
57EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
58
59static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
60{
61 struct nft_af_info *afi;
62
63 list_for_each_entry(afi, &net->nft.af_info, list) {
64 if (afi->family == family)
65 return afi;
66 }
67 return NULL;
68}
69
70static struct nft_af_info *
71nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
72{
73 struct nft_af_info *afi;
74
75 afi = nft_afinfo_lookup(net, family);
76 if (afi != NULL)
77 return afi;
78#ifdef CONFIG_MODULES
79 if (autoload) {
80 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
81 request_module("nft-afinfo-%u", family);
82 nfnl_lock(NFNL_SUBSYS_NFTABLES);
83 afi = nft_afinfo_lookup(net, family);
84 if (afi != NULL)
85 return ERR_PTR(-EAGAIN);
86 }
87#endif
88 return ERR_PTR(-EAFNOSUPPORT);
89}
90
91/*
92 * Tables
93 */
94
95static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
96 const struct nlattr *nla)
97{
98 struct nft_table *table;
99
100 list_for_each_entry(table, &afi->tables, list) {
101 if (!nla_strcmp(nla, table->name))
102 return table;
103 }
104 return NULL;
105}
106
107static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
108 const struct nlattr *nla)
109{
110 struct nft_table *table;
111
112 if (nla == NULL)
113 return ERR_PTR(-EINVAL);
114
115 table = nft_table_lookup(afi, nla);
116 if (table != NULL)
117 return table;
118
119 return ERR_PTR(-ENOENT);
120}
121
122static inline u64 nf_tables_alloc_handle(struct nft_table *table)
123{
124 return ++table->hgenerator;
125}
126
127static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
128
129static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
130{
131 int i;
132
133 for (i=0; i<NFT_CHAIN_T_MAX; i++) {
134 if (chain_type[family][i] != NULL &&
135 !nla_strcmp(nla, chain_type[family][i]->name))
136 return i;
137 }
138 return -1;
139}
140
141static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
142 const struct nlattr *nla,
143 bool autoload)
144{
145 int type;
146
147 type = __nf_tables_chain_type_lookup(afi->family, nla);
148#ifdef CONFIG_MODULES
149 if (type < 0 && autoload) {
150 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
151 request_module("nft-chain-%u-%*.s", afi->family,
152 nla_len(nla)-1, (const char *)nla_data(nla));
153 nfnl_lock(NFNL_SUBSYS_NFTABLES);
154 type = __nf_tables_chain_type_lookup(afi->family, nla);
155 }
156#endif
157 return type;
158}
159
160static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
161 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
162 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
163};
164
165static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
166 int event, u32 flags, int family,
167 const struct nft_table *table)
168{
169 struct nlmsghdr *nlh;
170 struct nfgenmsg *nfmsg;
171
172 event |= NFNL_SUBSYS_NFTABLES << 8;
173 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
174 if (nlh == NULL)
175 goto nla_put_failure;
176
177 nfmsg = nlmsg_data(nlh);
178 nfmsg->nfgen_family = family;
179 nfmsg->version = NFNETLINK_V0;
180 nfmsg->res_id = 0;
181
182 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
183 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)))
184 goto nla_put_failure;
185
186 return nlmsg_end(skb, nlh);
187
188nla_put_failure:
189 nlmsg_trim(skb, nlh);
190 return -1;
191}
192
193static int nf_tables_table_notify(const struct sk_buff *oskb,
194 const struct nlmsghdr *nlh,
195 const struct nft_table *table,
196 int event, int family)
197{
198 struct sk_buff *skb;
199 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
200 u32 seq = nlh ? nlh->nlmsg_seq : 0;
201 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
202 bool report;
203 int err;
204
205 report = nlh ? nlmsg_report(nlh) : false;
206 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
207 return 0;
208
209 err = -ENOBUFS;
210 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
211 if (skb == NULL)
212 goto err;
213
214 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
215 family, table);
216 if (err < 0) {
217 kfree_skb(skb);
218 goto err;
219 }
220
221 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
222 GFP_KERNEL);
223err:
224 if (err < 0)
225 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
226 return err;
227}
228
229static int nf_tables_dump_tables(struct sk_buff *skb,
230 struct netlink_callback *cb)
231{
232 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
233 const struct nft_af_info *afi;
234 const struct nft_table *table;
235 unsigned int idx = 0, s_idx = cb->args[0];
236 struct net *net = sock_net(skb->sk);
237 int family = nfmsg->nfgen_family;
238
239 list_for_each_entry(afi, &net->nft.af_info, list) {
240 if (family != NFPROTO_UNSPEC && family != afi->family)
241 continue;
242
243 list_for_each_entry(table, &afi->tables, list) {
244 if (idx < s_idx)
245 goto cont;
246 if (idx > s_idx)
247 memset(&cb->args[1], 0,
248 sizeof(cb->args) - sizeof(cb->args[0]));
249 if (nf_tables_fill_table_info(skb,
250 NETLINK_CB(cb->skb).portid,
251 cb->nlh->nlmsg_seq,
252 NFT_MSG_NEWTABLE,
253 NLM_F_MULTI,
254 afi->family, table) < 0)
255 goto done;
256cont:
257 idx++;
258 }
259 }
260done:
261 cb->args[0] = idx;
262 return skb->len;
263}
264
265static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
266 const struct nlmsghdr *nlh,
267 const struct nlattr * const nla[])
268{
269 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
270 const struct nft_af_info *afi;
271 const struct nft_table *table;
272 struct sk_buff *skb2;
273 struct net *net = sock_net(skb->sk);
274 int family = nfmsg->nfgen_family;
275 int err;
276
277 if (nlh->nlmsg_flags & NLM_F_DUMP) {
278 struct netlink_dump_control c = {
279 .dump = nf_tables_dump_tables,
280 };
281 return netlink_dump_start(nlsk, skb, nlh, &c);
282 }
283
284 afi = nf_tables_afinfo_lookup(net, family, false);
285 if (IS_ERR(afi))
286 return PTR_ERR(afi);
287
288 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
289 if (IS_ERR(table))
290 return PTR_ERR(table);
291
292 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
293 if (!skb2)
294 return -ENOMEM;
295
296 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
297 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
298 family, table);
299 if (err < 0)
300 goto err;
301
302 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
303
304err:
305 kfree_skb(skb2);
306 return err;
307}
308
309static int nf_tables_table_enable(struct nft_table *table)
310{
311 struct nft_chain *chain;
312 int err, i = 0;
313
314 list_for_each_entry(chain, &table->chains, list) {
315 err = nf_register_hook(&nft_base_chain(chain)->ops);
316 if (err < 0)
317 goto err;
318
319 i++;
320 }
321 return 0;
322err:
323 list_for_each_entry(chain, &table->chains, list) {
324 if (i-- <= 0)
325 break;
326
327 nf_unregister_hook(&nft_base_chain(chain)->ops);
328 }
329 return err;
330}
331
332static int nf_tables_table_disable(struct nft_table *table)
333{
334 struct nft_chain *chain;
335
336 list_for_each_entry(chain, &table->chains, list)
337 nf_unregister_hook(&nft_base_chain(chain)->ops);
338
339 return 0;
340}
341
342static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
343 const struct nlmsghdr *nlh,
344 const struct nlattr * const nla[],
345 struct nft_af_info *afi, struct nft_table *table)
346{
347 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
348 int family = nfmsg->nfgen_family, ret = 0;
349
350 if (nla[NFTA_TABLE_FLAGS]) {
351 __be32 flags;
352
353 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
354 if (flags & ~NFT_TABLE_F_DORMANT)
355 return -EINVAL;
356
357 if ((flags & NFT_TABLE_F_DORMANT) &&
358 !(table->flags & NFT_TABLE_F_DORMANT)) {
359 ret = nf_tables_table_disable(table);
360 if (ret >= 0)
361 table->flags |= NFT_TABLE_F_DORMANT;
362 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
363 table->flags & NFT_TABLE_F_DORMANT) {
364 ret = nf_tables_table_enable(table);
365 if (ret >= 0)
366 table->flags &= ~NFT_TABLE_F_DORMANT;
367 }
368 if (ret < 0)
369 goto err;
370 }
371
372 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
373err:
374 return ret;
375}
376
377static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
378 const struct nlmsghdr *nlh,
379 const struct nlattr * const nla[])
380{
381 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
382 const struct nlattr *name;
383 struct nft_af_info *afi;
384 struct nft_table *table;
385 struct net *net = sock_net(skb->sk);
386 int family = nfmsg->nfgen_family;
387
388 afi = nf_tables_afinfo_lookup(net, family, true);
389 if (IS_ERR(afi))
390 return PTR_ERR(afi);
391
392 name = nla[NFTA_TABLE_NAME];
393 table = nf_tables_table_lookup(afi, name);
394 if (IS_ERR(table)) {
395 if (PTR_ERR(table) != -ENOENT)
396 return PTR_ERR(table);
397 table = NULL;
398 }
399
400 if (table != NULL) {
401 if (nlh->nlmsg_flags & NLM_F_EXCL)
402 return -EEXIST;
403 if (nlh->nlmsg_flags & NLM_F_REPLACE)
404 return -EOPNOTSUPP;
405 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
406 }
407
408 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
409 if (table == NULL)
410 return -ENOMEM;
411
412 nla_strlcpy(table->name, name, nla_len(name));
413 INIT_LIST_HEAD(&table->chains);
414 INIT_LIST_HEAD(&table->sets);
415
416 if (nla[NFTA_TABLE_FLAGS]) {
417 __be32 flags;
418
419 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
420 if (flags & ~NFT_TABLE_F_DORMANT) {
421 kfree(table);
422 return -EINVAL;
423 }
424
425 table->flags |= flags;
426 }
427
428 list_add_tail(&table->list, &afi->tables);
429 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
430 return 0;
431}
432
433static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
434 const struct nlmsghdr *nlh,
435 const struct nlattr * const nla[])
436{
437 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
438 struct nft_af_info *afi;
439 struct nft_table *table;
440 struct net *net = sock_net(skb->sk);
441 int family = nfmsg->nfgen_family;
442
443 afi = nf_tables_afinfo_lookup(net, family, false);
444 if (IS_ERR(afi))
445 return PTR_ERR(afi);
446
447 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
448 if (IS_ERR(table))
449 return PTR_ERR(table);
450
451 if (table->use)
452 return -EBUSY;
453
454 list_del(&table->list);
455 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
456 kfree(table);
457 return 0;
458}
459
460int nft_register_chain_type(struct nf_chain_type *ctype)
461{
462 int err = 0;
463
464 nfnl_lock(NFNL_SUBSYS_NFTABLES);
465 if (chain_type[ctype->family][ctype->type] != NULL) {
466 err = -EBUSY;
467 goto out;
468 }
469
470 if (!try_module_get(ctype->me))
471 goto out;
472
473 chain_type[ctype->family][ctype->type] = ctype;
474out:
475 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
476 return err;
477}
478EXPORT_SYMBOL_GPL(nft_register_chain_type);
479
480void nft_unregister_chain_type(struct nf_chain_type *ctype)
481{
482 nfnl_lock(NFNL_SUBSYS_NFTABLES);
483 chain_type[ctype->family][ctype->type] = NULL;
484 module_put(ctype->me);
485 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
486}
487EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
488
489/*
490 * Chains
491 */
492
493static struct nft_chain *
494nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
495{
496 struct nft_chain *chain;
497
498 list_for_each_entry(chain, &table->chains, list) {
499 if (chain->handle == handle)
500 return chain;
501 }
502
503 return ERR_PTR(-ENOENT);
504}
505
506static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
507 const struct nlattr *nla)
508{
509 struct nft_chain *chain;
510
511 if (nla == NULL)
512 return ERR_PTR(-EINVAL);
513
514 list_for_each_entry(chain, &table->chains, list) {
515 if (!nla_strcmp(nla, chain->name))
516 return chain;
517 }
518
519 return ERR_PTR(-ENOENT);
520}
521
522static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
523 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
524 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
525 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
526 .len = NFT_CHAIN_MAXNAMELEN - 1 },
527 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
528 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
529 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
530 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
531};
532
533static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
534 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
535 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
536};
537
538static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
539{
540 struct nft_stats *cpu_stats, total;
541 struct nlattr *nest;
542 int cpu;
543
544 memset(&total, 0, sizeof(total));
545 for_each_possible_cpu(cpu) {
546 cpu_stats = per_cpu_ptr(stats, cpu);
547 total.pkts += cpu_stats->pkts;
548 total.bytes += cpu_stats->bytes;
549 }
550 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
551 if (nest == NULL)
552 goto nla_put_failure;
553
554 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
555 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
556 goto nla_put_failure;
557
558 nla_nest_end(skb, nest);
559 return 0;
560
561nla_put_failure:
562 return -ENOSPC;
563}
564
565static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
566 int event, u32 flags, int family,
567 const struct nft_table *table,
568 const struct nft_chain *chain)
569{
570 struct nlmsghdr *nlh;
571 struct nfgenmsg *nfmsg;
572
573 event |= NFNL_SUBSYS_NFTABLES << 8;
574 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
575 if (nlh == NULL)
576 goto nla_put_failure;
577
578 nfmsg = nlmsg_data(nlh);
579 nfmsg->nfgen_family = family;
580 nfmsg->version = NFNETLINK_V0;
581 nfmsg->res_id = 0;
582
583 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
584 goto nla_put_failure;
585 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
586 goto nla_put_failure;
587 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
588 goto nla_put_failure;
589
590 if (chain->flags & NFT_BASE_CHAIN) {
591 const struct nft_base_chain *basechain = nft_base_chain(chain);
592 const struct nf_hook_ops *ops = &basechain->ops;
593 struct nlattr *nest;
594
595 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
596 if (nest == NULL)
597 goto nla_put_failure;
598 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
599 goto nla_put_failure;
600 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
601 goto nla_put_failure;
602 nla_nest_end(skb, nest);
603
604 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
605 htonl(basechain->policy)))
606 goto nla_put_failure;
607
608 if (nla_put_string(skb, NFTA_CHAIN_TYPE,
609 chain_type[ops->pf][nft_base_chain(chain)->type]->name))
610 goto nla_put_failure;
611
612 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
613 goto nla_put_failure;
614 }
615
616 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
617 goto nla_put_failure;
618
619 return nlmsg_end(skb, nlh);
620
621nla_put_failure:
622 nlmsg_trim(skb, nlh);
623 return -1;
624}
625
626static int nf_tables_chain_notify(const struct sk_buff *oskb,
627 const struct nlmsghdr *nlh,
628 const struct nft_table *table,
629 const struct nft_chain *chain,
630 int event, int family)
631{
632 struct sk_buff *skb;
633 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
634 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
635 u32 seq = nlh ? nlh->nlmsg_seq : 0;
636 bool report;
637 int err;
638
639 report = nlh ? nlmsg_report(nlh) : false;
640 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
641 return 0;
642
643 err = -ENOBUFS;
644 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
645 if (skb == NULL)
646 goto err;
647
648 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
649 table, chain);
650 if (err < 0) {
651 kfree_skb(skb);
652 goto err;
653 }
654
655 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
656 GFP_KERNEL);
657err:
658 if (err < 0)
659 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
660 return err;
661}
662
663static int nf_tables_dump_chains(struct sk_buff *skb,
664 struct netlink_callback *cb)
665{
666 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
667 const struct nft_af_info *afi;
668 const struct nft_table *table;
669 const struct nft_chain *chain;
670 unsigned int idx = 0, s_idx = cb->args[0];
671 struct net *net = sock_net(skb->sk);
672 int family = nfmsg->nfgen_family;
673
674 list_for_each_entry(afi, &net->nft.af_info, list) {
675 if (family != NFPROTO_UNSPEC && family != afi->family)
676 continue;
677
678 list_for_each_entry(table, &afi->tables, list) {
679 list_for_each_entry(chain, &table->chains, list) {
680 if (idx < s_idx)
681 goto cont;
682 if (idx > s_idx)
683 memset(&cb->args[1], 0,
684 sizeof(cb->args) - sizeof(cb->args[0]));
685 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
686 cb->nlh->nlmsg_seq,
687 NFT_MSG_NEWCHAIN,
688 NLM_F_MULTI,
689 afi->family, table, chain) < 0)
690 goto done;
691cont:
692 idx++;
693 }
694 }
695 }
696done:
697 cb->args[0] = idx;
698 return skb->len;
699}
700
701
702static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
703 const struct nlmsghdr *nlh,
704 const struct nlattr * const nla[])
705{
706 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
707 const struct nft_af_info *afi;
708 const struct nft_table *table;
709 const struct nft_chain *chain;
710 struct sk_buff *skb2;
711 struct net *net = sock_net(skb->sk);
712 int family = nfmsg->nfgen_family;
713 int err;
714
715 if (nlh->nlmsg_flags & NLM_F_DUMP) {
716 struct netlink_dump_control c = {
717 .dump = nf_tables_dump_chains,
718 };
719 return netlink_dump_start(nlsk, skb, nlh, &c);
720 }
721
722 afi = nf_tables_afinfo_lookup(net, family, false);
723 if (IS_ERR(afi))
724 return PTR_ERR(afi);
725
726 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
727 if (IS_ERR(table))
728 return PTR_ERR(table);
729
730 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
731 if (IS_ERR(chain))
732 return PTR_ERR(chain);
733
734 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
735 if (!skb2)
736 return -ENOMEM;
737
738 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
739 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
740 family, table, chain);
741 if (err < 0)
742 goto err;
743
744 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
745
746err:
747 kfree_skb(skb2);
748 return err;
749}
750
751static int
752nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
753{
754 switch (ntohl(nla_get_be32(attr))) {
755 case NF_DROP:
756 chain->policy = NF_DROP;
757 break;
758 case NF_ACCEPT:
759 chain->policy = NF_ACCEPT;
760 break;
761 default:
762 return -EINVAL;
763 }
764 return 0;
765}
766
767static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
768 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
769 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
770};
771
772static int
773nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
774{
775 struct nlattr *tb[NFTA_COUNTER_MAX+1];
776 struct nft_stats __percpu *newstats;
777 struct nft_stats *stats;
778 int err;
779
780 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
781 if (err < 0)
782 return err;
783
784 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
785 return -EINVAL;
786
787 newstats = alloc_percpu(struct nft_stats);
788 if (newstats == NULL)
789 return -ENOMEM;
790
791 /* Restore old counters on this cpu, no problem. Per-cpu statistics
792 * are not exposed to userspace.
793 */
794 stats = this_cpu_ptr(newstats);
795 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
796 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
797
798 if (chain->stats) {
799 /* nfnl_lock is held, add some nfnl function for this, later */
800 struct nft_stats __percpu *oldstats =
801 rcu_dereference_protected(chain->stats, 1);
802
803 rcu_assign_pointer(chain->stats, newstats);
804 synchronize_rcu();
805 free_percpu(oldstats);
806 } else
807 rcu_assign_pointer(chain->stats, newstats);
808
809 return 0;
810}
811
812static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
813 const struct nlmsghdr *nlh,
814 const struct nlattr * const nla[])
815{
816 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
817 const struct nlattr * uninitialized_var(name);
818 const struct nft_af_info *afi;
819 struct nft_table *table;
820 struct nft_chain *chain;
821 struct nft_base_chain *basechain = NULL;
822 struct nlattr *ha[NFTA_HOOK_MAX + 1];
823 struct net *net = sock_net(skb->sk);
824 int family = nfmsg->nfgen_family;
825 u64 handle = 0;
826 int err;
827 bool create;
828
829 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
830
831 afi = nf_tables_afinfo_lookup(net, family, true);
832 if (IS_ERR(afi))
833 return PTR_ERR(afi);
834
835 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
836 if (IS_ERR(table))
837 return PTR_ERR(table);
838
839 if (table->use == UINT_MAX)
840 return -EOVERFLOW;
841
842 chain = NULL;
843 name = nla[NFTA_CHAIN_NAME];
844
845 if (nla[NFTA_CHAIN_HANDLE]) {
846 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
847 chain = nf_tables_chain_lookup_byhandle(table, handle);
848 if (IS_ERR(chain))
849 return PTR_ERR(chain);
850 } else {
851 chain = nf_tables_chain_lookup(table, name);
852 if (IS_ERR(chain)) {
853 if (PTR_ERR(chain) != -ENOENT)
854 return PTR_ERR(chain);
855 chain = NULL;
856 }
857 }
858
859 if (chain != NULL) {
860 if (nlh->nlmsg_flags & NLM_F_EXCL)
861 return -EEXIST;
862 if (nlh->nlmsg_flags & NLM_F_REPLACE)
863 return -EOPNOTSUPP;
864
865 if (nla[NFTA_CHAIN_HANDLE] && name &&
866 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
867 return -EEXIST;
868
869 if (nla[NFTA_CHAIN_POLICY]) {
870 if (!(chain->flags & NFT_BASE_CHAIN))
871 return -EOPNOTSUPP;
872
873 err = nf_tables_chain_policy(nft_base_chain(chain),
874 nla[NFTA_CHAIN_POLICY]);
875 if (err < 0)
876 return err;
877 }
878
879 if (nla[NFTA_CHAIN_COUNTERS]) {
880 if (!(chain->flags & NFT_BASE_CHAIN))
881 return -EOPNOTSUPP;
882
883 err = nf_tables_counters(nft_base_chain(chain),
884 nla[NFTA_CHAIN_COUNTERS]);
885 if (err < 0)
886 return err;
887 }
888
889 if (nla[NFTA_CHAIN_HANDLE] && name)
890 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
891
892 goto notify;
893 }
894
895 if (nla[NFTA_CHAIN_HOOK]) {
896 struct nf_hook_ops *ops;
897 nf_hookfn *hookfn;
898 u32 hooknum;
899 int type = NFT_CHAIN_T_DEFAULT;
900
901 if (nla[NFTA_CHAIN_TYPE]) {
902 type = nf_tables_chain_type_lookup(afi,
903 nla[NFTA_CHAIN_TYPE],
904 create);
905 if (type < 0)
906 return -ENOENT;
907 }
908
909 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
910 nft_hook_policy);
911 if (err < 0)
912 return err;
913 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
914 ha[NFTA_HOOK_PRIORITY] == NULL)
915 return -EINVAL;
916
917 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
918 if (hooknum >= afi->nhooks)
919 return -EINVAL;
920
921 hookfn = chain_type[family][type]->fn[hooknum];
922 if (hookfn == NULL)
923 return -EOPNOTSUPP;
924
925 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
926 if (basechain == NULL)
927 return -ENOMEM;
928
929 basechain->type = type;
930 chain = &basechain->chain;
931
932 ops = &basechain->ops;
933 ops->pf = family;
934 ops->owner = afi->owner;
935 ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
936 ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
937 ops->priv = chain;
938 ops->hook = hookfn;
939 if (afi->hooks[ops->hooknum])
940 ops->hook = afi->hooks[ops->hooknum];
941
942 chain->flags |= NFT_BASE_CHAIN;
943
944 if (nla[NFTA_CHAIN_POLICY]) {
945 err = nf_tables_chain_policy(basechain,
946 nla[NFTA_CHAIN_POLICY]);
947 if (err < 0) {
948 free_percpu(basechain->stats);
949 kfree(basechain);
950 return err;
951 }
952 } else
953 basechain->policy = NF_ACCEPT;
954
955 if (nla[NFTA_CHAIN_COUNTERS]) {
956 err = nf_tables_counters(basechain,
957 nla[NFTA_CHAIN_COUNTERS]);
958 if (err < 0) {
959 free_percpu(basechain->stats);
960 kfree(basechain);
961 return err;
962 }
963 } else {
964 struct nft_stats __percpu *newstats;
965
966 newstats = alloc_percpu(struct nft_stats);
967 if (newstats == NULL)
968 return -ENOMEM;
969
970 rcu_assign_pointer(nft_base_chain(chain)->stats,
971 newstats);
972 }
973 } else {
974 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
975 if (chain == NULL)
976 return -ENOMEM;
977 }
978
979 INIT_LIST_HEAD(&chain->rules);
980 chain->handle = nf_tables_alloc_handle(table);
981 chain->net = net;
982 chain->table = table;
983 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
984
985 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
986 chain->flags & NFT_BASE_CHAIN) {
987 err = nf_register_hook(&nft_base_chain(chain)->ops);
988 if (err < 0) {
989 free_percpu(basechain->stats);
990 kfree(basechain);
991 return err;
992 }
993 }
994 list_add_tail(&chain->list, &table->chains);
995 table->use++;
996notify:
997 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
998 family);
999 return 0;
1000}
1001
1002static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
1003{
1004 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
1005
1006 BUG_ON(chain->use > 0);
1007
1008 if (chain->flags & NFT_BASE_CHAIN) {
1009 free_percpu(nft_base_chain(chain)->stats);
1010 kfree(nft_base_chain(chain));
1011 } else
1012 kfree(chain);
1013}
1014
1015static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1016 const struct nlmsghdr *nlh,
1017 const struct nlattr * const nla[])
1018{
1019 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1020 const struct nft_af_info *afi;
1021 struct nft_table *table;
1022 struct nft_chain *chain;
1023 struct net *net = sock_net(skb->sk);
1024 int family = nfmsg->nfgen_family;
1025
1026 afi = nf_tables_afinfo_lookup(net, family, false);
1027 if (IS_ERR(afi))
1028 return PTR_ERR(afi);
1029
1030 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
1031 if (IS_ERR(table))
1032 return PTR_ERR(table);
1033
1034 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1035 if (IS_ERR(chain))
1036 return PTR_ERR(chain);
1037
1038 if (!list_empty(&chain->rules))
1039 return -EBUSY;
1040
1041 list_del(&chain->list);
1042 table->use--;
1043
1044 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1045 chain->flags & NFT_BASE_CHAIN)
1046 nf_unregister_hook(&nft_base_chain(chain)->ops);
1047
1048 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1049 family);
1050
1051 /* Make sure all rule references are gone before this is released */
1052 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
1053 return 0;
1054}
1055
1056static void nft_ctx_init(struct nft_ctx *ctx,
1057 const struct sk_buff *skb,
1058 const struct nlmsghdr *nlh,
1059 const struct nft_af_info *afi,
1060 const struct nft_table *table,
1061 const struct nft_chain *chain,
1062 const struct nlattr * const *nla)
1063{
1064 ctx->net = sock_net(skb->sk);
1065 ctx->skb = skb;
1066 ctx->nlh = nlh;
1067 ctx->afi = afi;
1068 ctx->table = table;
1069 ctx->chain = chain;
1070 ctx->nla = nla;
1071}
1072
1073/*
1074 * Expressions
1075 */
1076
1077/**
1078 * nft_register_expr - register nf_tables expr type
1079 * @ops: expr type
1080 *
1081 * Registers the expr type for use with nf_tables. Returns zero on
1082 * success or a negative errno code otherwise.
1083 */
1084int nft_register_expr(struct nft_expr_type *type)
1085{
1086 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1087 list_add_tail(&type->list, &nf_tables_expressions);
1088 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1089 return 0;
1090}
1091EXPORT_SYMBOL_GPL(nft_register_expr);
1092
1093/**
1094 * nft_unregister_expr - unregister nf_tables expr type
1095 * @ops: expr type
1096 *
1097 * Unregisters the expr typefor use with nf_tables.
1098 */
1099void nft_unregister_expr(struct nft_expr_type *type)
1100{
1101 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1102 list_del(&type->list);
1103 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1104}
1105EXPORT_SYMBOL_GPL(nft_unregister_expr);
1106
1107static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
1108{
1109 const struct nft_expr_type *type;
1110
1111 list_for_each_entry(type, &nf_tables_expressions, list) {
1112 if (!nla_strcmp(nla, type->name))
1113 return type;
1114 }
1115 return NULL;
1116}
1117
1118static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
1119{
1120 const struct nft_expr_type *type;
1121
1122 if (nla == NULL)
1123 return ERR_PTR(-EINVAL);
1124
1125 type = __nft_expr_type_get(nla);
1126 if (type != NULL && try_module_get(type->owner))
1127 return type;
1128
1129#ifdef CONFIG_MODULES
1130 if (type == NULL) {
1131 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1132 request_module("nft-expr-%.*s",
1133 nla_len(nla), (char *)nla_data(nla));
1134 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1135 if (__nft_expr_type_get(nla))
1136 return ERR_PTR(-EAGAIN);
1137 }
1138#endif
1139 return ERR_PTR(-ENOENT);
1140}
1141
1142static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1143 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1144 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1145};
1146
1147static int nf_tables_fill_expr_info(struct sk_buff *skb,
1148 const struct nft_expr *expr)
1149{
1150 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
1151 goto nla_put_failure;
1152
1153 if (expr->ops->dump) {
1154 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1155 if (data == NULL)
1156 goto nla_put_failure;
1157 if (expr->ops->dump(skb, expr) < 0)
1158 goto nla_put_failure;
1159 nla_nest_end(skb, data);
1160 }
1161
1162 return skb->len;
1163
1164nla_put_failure:
1165 return -1;
1166};
1167
1168struct nft_expr_info {
1169 const struct nft_expr_ops *ops;
1170 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
1171};
1172
1173static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1174 const struct nlattr *nla,
1175 struct nft_expr_info *info)
1176{
1177 const struct nft_expr_type *type;
1178 const struct nft_expr_ops *ops;
1179 struct nlattr *tb[NFTA_EXPR_MAX + 1];
1180 int err;
1181
1182 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
1183 if (err < 0)
1184 return err;
1185
1186 type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
1187 if (IS_ERR(type))
1188 return PTR_ERR(type);
1189
1190 if (tb[NFTA_EXPR_DATA]) {
1191 err = nla_parse_nested(info->tb, type->maxattr,
1192 tb[NFTA_EXPR_DATA], type->policy);
1193 if (err < 0)
1194 goto err1;
1195 } else
1196 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1197
1198 if (type->select_ops != NULL) {
1199 ops = type->select_ops(ctx,
1200 (const struct nlattr * const *)info->tb);
1201 if (IS_ERR(ops)) {
1202 err = PTR_ERR(ops);
1203 goto err1;
1204 }
1205 } else
1206 ops = type->ops;
1207
1208 info->ops = ops;
1209 return 0;
1210
1211err1:
1212 module_put(type->owner);
1213 return err;
1214}
1215
1216static int nf_tables_newexpr(const struct nft_ctx *ctx,
1217 const struct nft_expr_info *info,
1218 struct nft_expr *expr)
1219{
1220 const struct nft_expr_ops *ops = info->ops;
1221 int err;
1222
1223 expr->ops = ops;
1224 if (ops->init) {
1225 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
1226 if (err < 0)
1227 goto err1;
1228 }
1229
1230 return 0;
1231
1232err1:
1233 expr->ops = NULL;
1234 return err;
1235}
1236
1237static void nf_tables_expr_destroy(struct nft_expr *expr)
1238{
1239 if (expr->ops->destroy)
1240 expr->ops->destroy(expr);
1241 module_put(expr->ops->type->owner);
1242}
1243
1244/*
1245 * Rules
1246 */
1247
1248static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1249 u64 handle)
1250{
1251 struct nft_rule *rule;
1252
1253 // FIXME: this sucks
1254 list_for_each_entry(rule, &chain->rules, list) {
1255 if (handle == rule->handle)
1256 return rule;
1257 }
1258
1259 return ERR_PTR(-ENOENT);
1260}
1261
1262static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1263 const struct nlattr *nla)
1264{
1265 if (nla == NULL)
1266 return ERR_PTR(-EINVAL);
1267
1268 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1269}
1270
1271static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1272 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1273 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1274 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1275 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1276 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
1277 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
1278 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
1279};
1280
1281static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1282 int event, u32 flags, int family,
1283 const struct nft_table *table,
1284 const struct nft_chain *chain,
1285 const struct nft_rule *rule)
1286{
1287 struct nlmsghdr *nlh;
1288 struct nfgenmsg *nfmsg;
1289 const struct nft_expr *expr, *next;
1290 struct nlattr *list;
1291 const struct nft_rule *prule;
1292 int type = event | NFNL_SUBSYS_NFTABLES << 8;
1293
1294 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
1295 flags);
1296 if (nlh == NULL)
1297 goto nla_put_failure;
1298
1299 nfmsg = nlmsg_data(nlh);
1300 nfmsg->nfgen_family = family;
1301 nfmsg->version = NFNETLINK_V0;
1302 nfmsg->res_id = 0;
1303
1304 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1305 goto nla_put_failure;
1306 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1307 goto nla_put_failure;
1308 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1309 goto nla_put_failure;
1310
1311 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1312 prule = list_entry(rule->list.prev, struct nft_rule, list);
1313 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1314 cpu_to_be64(prule->handle)))
1315 goto nla_put_failure;
1316 }
1317
1318 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1319 if (list == NULL)
1320 goto nla_put_failure;
1321 nft_rule_for_each_expr(expr, next, rule) {
1322 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1323 if (elem == NULL)
1324 goto nla_put_failure;
1325 if (nf_tables_fill_expr_info(skb, expr) < 0)
1326 goto nla_put_failure;
1327 nla_nest_end(skb, elem);
1328 }
1329 nla_nest_end(skb, list);
1330
1331 return nlmsg_end(skb, nlh);
1332
1333nla_put_failure:
1334 nlmsg_trim(skb, nlh);
1335 return -1;
1336}
1337
1338static int nf_tables_rule_notify(const struct sk_buff *oskb,
1339 const struct nlmsghdr *nlh,
1340 const struct nft_table *table,
1341 const struct nft_chain *chain,
1342 const struct nft_rule *rule,
1343 int event, u32 flags, int family)
1344{
1345 struct sk_buff *skb;
1346 u32 portid = NETLINK_CB(oskb).portid;
1347 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1348 u32 seq = nlh->nlmsg_seq;
1349 bool report;
1350 int err;
1351
1352 report = nlmsg_report(nlh);
1353 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1354 return 0;
1355
1356 err = -ENOBUFS;
1357 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1358 if (skb == NULL)
1359 goto err;
1360
1361 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1362 family, table, chain, rule);
1363 if (err < 0) {
1364 kfree_skb(skb);
1365 goto err;
1366 }
1367
1368 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1369 GFP_KERNEL);
1370err:
1371 if (err < 0)
1372 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1373 return err;
1374}
1375
1376static inline bool
1377nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1378{
1379 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1380}
1381
1382static inline int gencursor_next(struct net *net)
1383{
1384 return net->nft.gencursor+1 == 1 ? 1 : 0;
1385}
1386
1387static inline int
1388nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1389{
1390 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1391}
1392
1393static inline void
1394nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1395{
1396 /* Now inactive, will be active in the future */
1397 rule->genmask = (1 << net->nft.gencursor);
1398}
1399
1400static inline void
1401nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1402{
1403 rule->genmask = (1 << gencursor_next(net));
1404}
1405
1406static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1407{
1408 rule->genmask = 0;
1409}
1410
1411static int nf_tables_dump_rules(struct sk_buff *skb,
1412 struct netlink_callback *cb)
1413{
1414 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1415 const struct nft_af_info *afi;
1416 const struct nft_table *table;
1417 const struct nft_chain *chain;
1418 const struct nft_rule *rule;
1419 unsigned int idx = 0, s_idx = cb->args[0];
1420 struct net *net = sock_net(skb->sk);
1421 int family = nfmsg->nfgen_family;
1422 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1423 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
1424
1425 list_for_each_entry(afi, &net->nft.af_info, list) {
1426 if (family != NFPROTO_UNSPEC && family != afi->family)
1427 continue;
1428
1429 list_for_each_entry(table, &afi->tables, list) {
1430 list_for_each_entry(chain, &table->chains, list) {
1431 list_for_each_entry(rule, &chain->rules, list) {
1432 if (!nft_rule_is_active(net, rule))
1433 goto cont;
1434 if (idx < s_idx)
1435 goto cont;
1436 if (idx > s_idx)
1437 memset(&cb->args[1], 0,
1438 sizeof(cb->args) - sizeof(cb->args[0]));
1439 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1440 cb->nlh->nlmsg_seq,
1441 NFT_MSG_NEWRULE,
1442 NLM_F_MULTI | NLM_F_APPEND,
1443 afi->family, table, chain, rule) < 0)
1444 goto done;
1445cont:
1446 idx++;
1447 }
1448 }
1449 }
1450 }
1451done:
1452 /* Invalidate this dump, a transition to the new generation happened */
1453 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1454 return -EBUSY;
1455
1456 cb->args[0] = idx;
1457 return skb->len;
1458}
1459
1460static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1461 const struct nlmsghdr *nlh,
1462 const struct nlattr * const nla[])
1463{
1464 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1465 const struct nft_af_info *afi;
1466 const struct nft_table *table;
1467 const struct nft_chain *chain;
1468 const struct nft_rule *rule;
1469 struct sk_buff *skb2;
1470 struct net *net = sock_net(skb->sk);
1471 int family = nfmsg->nfgen_family;
1472 int err;
1473
1474 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1475 struct netlink_dump_control c = {
1476 .dump = nf_tables_dump_rules,
1477 };
1478 return netlink_dump_start(nlsk, skb, nlh, &c);
1479 }
1480
1481 afi = nf_tables_afinfo_lookup(net, family, false);
1482 if (IS_ERR(afi))
1483 return PTR_ERR(afi);
1484
1485 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
1486 if (IS_ERR(table))
1487 return PTR_ERR(table);
1488
1489 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1490 if (IS_ERR(chain))
1491 return PTR_ERR(chain);
1492
1493 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1494 if (IS_ERR(rule))
1495 return PTR_ERR(rule);
1496
1497 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1498 if (!skb2)
1499 return -ENOMEM;
1500
1501 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1502 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1503 family, table, chain, rule);
1504 if (err < 0)
1505 goto err;
1506
1507 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1508
1509err:
1510 kfree_skb(skb2);
1511 return err;
1512}
1513
1514static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1515{
1516 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1517 struct nft_expr *expr;
1518
1519 /*
1520 * Careful: some expressions might not be initialized in case this
1521 * is called on error from nf_tables_newrule().
1522 */
1523 expr = nft_expr_first(rule);
1524 while (expr->ops && expr != nft_expr_last(rule)) {
1525 nf_tables_expr_destroy(expr);
1526 expr = nft_expr_next(expr);
1527 }
1528 kfree(rule);
1529}
1530
1531static void nf_tables_rule_destroy(struct nft_rule *rule)
1532{
1533 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1534}
1535
1536#define NFT_RULE_MAXEXPRS 128
1537
1538static struct nft_expr_info *info;
1539
1540static struct nft_rule_trans *
1541nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
1542{
1543 struct nft_rule_trans *rupd;
1544
1545 rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL);
1546 if (rupd == NULL)
1547 return NULL;
1548
1549 rupd->chain = ctx->chain;
1550 rupd->table = ctx->table;
1551 rupd->rule = rule;
1552 rupd->family = ctx->afi->family;
1553 rupd->nlh = ctx->nlh;
1554 list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
1555
1556 return rupd;
1557}
1558
1559static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1560 const struct nlmsghdr *nlh,
1561 const struct nlattr * const nla[])
1562{
1563 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1564 const struct nft_af_info *afi;
1565 struct net *net = sock_net(skb->sk);
1566 struct nft_table *table;
1567 struct nft_chain *chain;
1568 struct nft_rule *rule, *old_rule = NULL;
1569 struct nft_rule_trans *repl = NULL;
1570 struct nft_expr *expr;
1571 struct nft_ctx ctx;
1572 struct nlattr *tmp;
1573 unsigned int size, i, n;
1574 int err, rem;
1575 bool create;
1576 u64 handle, pos_handle;
1577
1578 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1579
1580 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
1581 if (IS_ERR(afi))
1582 return PTR_ERR(afi);
1583
1584 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
1585 if (IS_ERR(table))
1586 return PTR_ERR(table);
1587
1588 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1589 if (IS_ERR(chain))
1590 return PTR_ERR(chain);
1591
1592 if (nla[NFTA_RULE_HANDLE]) {
1593 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1594 rule = __nf_tables_rule_lookup(chain, handle);
1595 if (IS_ERR(rule))
1596 return PTR_ERR(rule);
1597
1598 if (nlh->nlmsg_flags & NLM_F_EXCL)
1599 return -EEXIST;
1600 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1601 old_rule = rule;
1602 else
1603 return -EOPNOTSUPP;
1604 } else {
1605 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1606 return -EINVAL;
1607 handle = nf_tables_alloc_handle(table);
1608 }
1609
1610 if (nla[NFTA_RULE_POSITION]) {
1611 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1612 return -EOPNOTSUPP;
1613
1614 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1615 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1616 if (IS_ERR(old_rule))
1617 return PTR_ERR(old_rule);
1618 }
1619
1620 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1621
1622 n = 0;
1623 size = 0;
1624 if (nla[NFTA_RULE_EXPRESSIONS]) {
1625 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1626 err = -EINVAL;
1627 if (nla_type(tmp) != NFTA_LIST_ELEM)
1628 goto err1;
1629 if (n == NFT_RULE_MAXEXPRS)
1630 goto err1;
1631 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
1632 if (err < 0)
1633 goto err1;
1634 size += info[n].ops->size;
1635 n++;
1636 }
1637 }
1638
1639 err = -ENOMEM;
1640 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1641 if (rule == NULL)
1642 goto err1;
1643
1644 nft_rule_activate_next(net, rule);
1645
1646 rule->handle = handle;
1647 rule->dlen = size;
1648
1649 expr = nft_expr_first(rule);
1650 for (i = 0; i < n; i++) {
1651 err = nf_tables_newexpr(&ctx, &info[i], expr);
1652 if (err < 0)
1653 goto err2;
1654 info[i].ops = NULL;
1655 expr = nft_expr_next(expr);
1656 }
1657
1658 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
1659 if (nft_rule_is_active_next(net, old_rule)) {
1660 repl = nf_tables_trans_add(old_rule, &ctx);
1661 if (repl == NULL) {
1662 err = -ENOMEM;
1663 goto err2;
1664 }
1665 nft_rule_disactivate_next(net, old_rule);
1666 list_add_tail(&rule->list, &old_rule->list);
1667 } else {
1668 err = -ENOENT;
1669 goto err2;
1670 }
1671 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
1672 if (old_rule)
1673 list_add_rcu(&rule->list, &old_rule->list);
1674 else
1675 list_add_tail_rcu(&rule->list, &chain->rules);
1676 else {
1677 if (old_rule)
1678 list_add_tail_rcu(&rule->list, &old_rule->list);
1679 else
1680 list_add_rcu(&rule->list, &chain->rules);
1681 }
1682
1683 if (nf_tables_trans_add(rule, &ctx) == NULL) {
1684 err = -ENOMEM;
1685 goto err3;
1686 }
1687 return 0;
1688
1689err3:
1690 list_del_rcu(&rule->list);
1691 if (repl) {
1692 list_del_rcu(&repl->rule->list);
1693 list_del(&repl->list);
1694 nft_rule_clear(net, repl->rule);
1695 kfree(repl);
1696 }
1697err2:
1698 nf_tables_rule_destroy(rule);
1699err1:
1700 for (i = 0; i < n; i++) {
1701 if (info[i].ops != NULL)
1702 module_put(info[i].ops->type->owner);
1703 }
1704 return err;
1705}
1706
1707static int
1708nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1709{
1710 /* You cannot delete the same rule twice */
1711 if (nft_rule_is_active_next(ctx->net, rule)) {
1712 if (nf_tables_trans_add(rule, ctx) == NULL)
1713 return -ENOMEM;
1714 nft_rule_disactivate_next(ctx->net, rule);
1715 return 0;
1716 }
1717 return -ENOENT;
1718}
1719
1720static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1721 const struct nlmsghdr *nlh,
1722 const struct nlattr * const nla[])
1723{
1724 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1725 const struct nft_af_info *afi;
1726 struct net *net = sock_net(skb->sk);
1727 const struct nft_table *table;
1728 struct nft_chain *chain;
1729 struct nft_rule *rule, *tmp;
1730 int family = nfmsg->nfgen_family, err = 0;
1731 struct nft_ctx ctx;
1732
1733 afi = nf_tables_afinfo_lookup(net, family, false);
1734 if (IS_ERR(afi))
1735 return PTR_ERR(afi);
1736
1737 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
1738 if (IS_ERR(table))
1739 return PTR_ERR(table);
1740
1741 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1742 if (IS_ERR(chain))
1743 return PTR_ERR(chain);
1744
1745 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1746
1747 if (nla[NFTA_RULE_HANDLE]) {
1748 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1749 if (IS_ERR(rule))
1750 return PTR_ERR(rule);
1751
1752 err = nf_tables_delrule_one(&ctx, rule);
1753 } else {
1754 /* Remove all rules in this chain */
1755 list_for_each_entry_safe(rule, tmp, &chain->rules, list) {
1756 err = nf_tables_delrule_one(&ctx, rule);
1757 if (err < 0)
1758 break;
1759 }
1760 }
1761
1762 return err;
1763}
1764
1765static int nf_tables_commit(struct sk_buff *skb)
1766{
1767 struct net *net = sock_net(skb->sk);
1768 struct nft_rule_trans *rupd, *tmp;
1769
1770 /* Bump generation counter, invalidate any dump in progress */
1771 net->nft.genctr++;
1772
1773 /* A new generation has just started */
1774 net->nft.gencursor = gencursor_next(net);
1775
1776 /* Make sure all packets have left the previous generation before
1777 * purging old rules.
1778 */
1779 synchronize_rcu();
1780
1781 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1782 /* Delete this rule from the dirty list */
1783 list_del(&rupd->list);
1784
1785 /* This rule was inactive in the past and just became active.
1786 * Clear the next bit of the genmask since its meaning has
1787 * changed, now it is the future.
1788 */
1789 if (nft_rule_is_active(net, rupd->rule)) {
1790 nft_rule_clear(net, rupd->rule);
1791 nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
1792 rupd->chain, rupd->rule,
1793 NFT_MSG_NEWRULE, 0,
1794 rupd->family);
1795 kfree(rupd);
1796 continue;
1797 }
1798
1799 /* This rule is in the past, get rid of it */
1800 list_del_rcu(&rupd->rule->list);
1801 nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
1802 rupd->rule, NFT_MSG_DELRULE, 0,
1803 rupd->family);
1804 nf_tables_rule_destroy(rupd->rule);
1805 kfree(rupd);
1806 }
1807
1808 return 0;
1809}
1810
1811static int nf_tables_abort(struct sk_buff *skb)
1812{
1813 struct net *net = sock_net(skb->sk);
1814 struct nft_rule_trans *rupd, *tmp;
1815
1816 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1817 /* Delete all rules from the dirty list */
1818 list_del(&rupd->list);
1819
1820 if (!nft_rule_is_active_next(net, rupd->rule)) {
1821 nft_rule_clear(net, rupd->rule);
1822 kfree(rupd);
1823 continue;
1824 }
1825
1826 /* This rule is inactive, get rid of it */
1827 list_del_rcu(&rupd->rule->list);
1828 nf_tables_rule_destroy(rupd->rule);
1829 kfree(rupd);
1830 }
1831 return 0;
1832}
1833
1834/*
1835 * Sets
1836 */
1837
1838static LIST_HEAD(nf_tables_set_ops);
1839
1840int nft_register_set(struct nft_set_ops *ops)
1841{
1842 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1843 list_add_tail(&ops->list, &nf_tables_set_ops);
1844 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1845 return 0;
1846}
1847EXPORT_SYMBOL_GPL(nft_register_set);
1848
1849void nft_unregister_set(struct nft_set_ops *ops)
1850{
1851 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1852 list_del(&ops->list);
1853 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1854}
1855EXPORT_SYMBOL_GPL(nft_unregister_set);
1856
1857static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1858{
1859 const struct nft_set_ops *ops;
1860 u32 features;
1861
1862#ifdef CONFIG_MODULES
1863 if (list_empty(&nf_tables_set_ops)) {
1864 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1865 request_module("nft-set");
1866 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1867 if (!list_empty(&nf_tables_set_ops))
1868 return ERR_PTR(-EAGAIN);
1869 }
1870#endif
1871 features = 0;
1872 if (nla[NFTA_SET_FLAGS] != NULL) {
1873 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1874 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1875 }
1876
1877 // FIXME: implement selection properly
1878 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1879 if ((ops->features & features) != features)
1880 continue;
1881 if (!try_module_get(ops->owner))
1882 continue;
1883 return ops;
1884 }
1885
1886 return ERR_PTR(-EOPNOTSUPP);
1887}
1888
1889static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1890 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1891 [NFTA_SET_NAME] = { .type = NLA_STRING },
1892 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1893 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1894 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1895 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1896 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1897};
1898
1899static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1900 const struct sk_buff *skb,
1901 const struct nlmsghdr *nlh,
1902 const struct nlattr * const nla[])
1903{
1904 struct net *net = sock_net(skb->sk);
1905 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1906 const struct nft_af_info *afi;
1907 const struct nft_table *table = NULL;
1908
1909 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
1910 if (IS_ERR(afi))
1911 return PTR_ERR(afi);
1912
1913 if (nla[NFTA_SET_TABLE] != NULL) {
1914 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
1915 if (IS_ERR(table))
1916 return PTR_ERR(table);
1917 }
1918
1919 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
1920 return 0;
1921}
1922
1923struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1924 const struct nlattr *nla)
1925{
1926 struct nft_set *set;
1927
1928 if (nla == NULL)
1929 return ERR_PTR(-EINVAL);
1930
1931 list_for_each_entry(set, &table->sets, list) {
1932 if (!nla_strcmp(nla, set->name))
1933 return set;
1934 }
1935 return ERR_PTR(-ENOENT);
1936}
1937
1938static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1939 const char *name)
1940{
1941 const struct nft_set *i;
1942 const char *p;
1943 unsigned long *inuse;
1944 unsigned int n = 0;
1945
1946 p = strnchr(name, IFNAMSIZ, '%');
1947 if (p != NULL) {
1948 if (p[1] != 'd' || strchr(p + 2, '%'))
1949 return -EINVAL;
1950
1951 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1952 if (inuse == NULL)
1953 return -ENOMEM;
1954
1955 list_for_each_entry(i, &ctx->table->sets, list) {
1956 if (!sscanf(i->name, name, &n))
1957 continue;
1958 if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE)
1959 continue;
1960 set_bit(n, inuse);
1961 }
1962
1963 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
1964 free_page((unsigned long)inuse);
1965 }
1966
1967 snprintf(set->name, sizeof(set->name), name, n);
1968 list_for_each_entry(i, &ctx->table->sets, list) {
1969 if (!strcmp(set->name, i->name))
1970 return -ENFILE;
1971 }
1972 return 0;
1973}
1974
1975static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
1976 const struct nft_set *set, u16 event, u16 flags)
1977{
1978 struct nfgenmsg *nfmsg;
1979 struct nlmsghdr *nlh;
1980 u32 portid = NETLINK_CB(ctx->skb).portid;
1981 u32 seq = ctx->nlh->nlmsg_seq;
1982
1983 event |= NFNL_SUBSYS_NFTABLES << 8;
1984 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1985 flags);
1986 if (nlh == NULL)
1987 goto nla_put_failure;
1988
1989 nfmsg = nlmsg_data(nlh);
1990 nfmsg->nfgen_family = ctx->afi->family;
1991 nfmsg->version = NFNETLINK_V0;
1992 nfmsg->res_id = 0;
1993
1994 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
1995 goto nla_put_failure;
1996 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
1997 goto nla_put_failure;
1998 if (set->flags != 0)
1999 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2000 goto nla_put_failure;
2001
2002 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2003 goto nla_put_failure;
2004 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2005 goto nla_put_failure;
2006 if (set->flags & NFT_SET_MAP) {
2007 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2008 goto nla_put_failure;
2009 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2010 goto nla_put_failure;
2011 }
2012
2013 return nlmsg_end(skb, nlh);
2014
2015nla_put_failure:
2016 nlmsg_trim(skb, nlh);
2017 return -1;
2018}
2019
2020static int nf_tables_set_notify(const struct nft_ctx *ctx,
2021 const struct nft_set *set,
2022 int event)
2023{
2024 struct sk_buff *skb;
2025 u32 portid = NETLINK_CB(ctx->skb).portid;
2026 bool report;
2027 int err;
2028
2029 report = nlmsg_report(ctx->nlh);
2030 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
2031 return 0;
2032
2033 err = -ENOBUFS;
2034 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2035 if (skb == NULL)
2036 goto err;
2037
2038 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2039 if (err < 0) {
2040 kfree_skb(skb);
2041 goto err;
2042 }
2043
2044 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
2045 GFP_KERNEL);
2046err:
2047 if (err < 0)
2048 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
2049 return err;
2050}
2051
2052static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2053 struct netlink_callback *cb)
2054{
2055 const struct nft_set *set;
2056 unsigned int idx = 0, s_idx = cb->args[0];
2057
2058 if (cb->args[1])
2059 return skb->len;
2060
2061 list_for_each_entry(set, &ctx->table->sets, list) {
2062 if (idx < s_idx)
2063 goto cont;
2064 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2065 NLM_F_MULTI) < 0) {
2066 cb->args[0] = idx;
2067 goto done;
2068 }
2069cont:
2070 idx++;
2071 }
2072 cb->args[1] = 1;
2073done:
2074 return skb->len;
2075}
2076
2077static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2078 struct netlink_callback *cb)
2079{
2080 const struct nft_set *set;
2081 unsigned int idx = 0, s_idx = cb->args[0];
2082 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2083
2084 if (cb->args[1])
2085 return skb->len;
2086
2087 list_for_each_entry(table, &ctx->afi->tables, list) {
2088 if (cur_table && cur_table != table)
2089 continue;
2090
2091 ctx->table = table;
2092 list_for_each_entry(set, &ctx->table->sets, list) {
2093 if (idx < s_idx)
2094 goto cont;
2095 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2096 NLM_F_MULTI) < 0) {
2097 cb->args[0] = idx;
2098 cb->args[2] = (unsigned long) table;
2099 goto done;
2100 }
2101cont:
2102 idx++;
2103 }
2104 }
2105 cb->args[1] = 1;
2106done:
2107 return skb->len;
2108}
2109
2110static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2111{
2112 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2113 struct nlattr *nla[NFTA_SET_MAX + 1];
2114 struct nft_ctx ctx;
2115 int err, ret;
2116
2117 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2118 nft_set_policy);
2119 if (err < 0)
2120 return err;
2121
2122 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2123 if (err < 0)
2124 return err;
2125
2126 if (ctx.table == NULL)
2127 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2128 else
2129 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2130
2131 return ret;
2132}
2133
2134static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2135 const struct nlmsghdr *nlh,
2136 const struct nlattr * const nla[])
2137{
2138 const struct nft_set *set;
2139 struct nft_ctx ctx;
2140 struct sk_buff *skb2;
2141 int err;
2142
2143 /* Verify existance before starting dump */
2144 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2145 if (err < 0)
2146 return err;
2147
2148 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2149 struct netlink_dump_control c = {
2150 .dump = nf_tables_dump_sets,
2151 };
2152 return netlink_dump_start(nlsk, skb, nlh, &c);
2153 }
2154
2155 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2156 if (IS_ERR(set))
2157 return PTR_ERR(set);
2158
2159 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2160 if (skb2 == NULL)
2161 return -ENOMEM;
2162
2163 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2164 if (err < 0)
2165 goto err;
2166
2167 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2168
2169err:
2170 kfree_skb(skb2);
2171 return err;
2172}
2173
2174static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2175 const struct nlmsghdr *nlh,
2176 const struct nlattr * const nla[])
2177{
2178 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2179 const struct nft_set_ops *ops;
2180 const struct nft_af_info *afi;
2181 struct net *net = sock_net(skb->sk);
2182 struct nft_table *table;
2183 struct nft_set *set;
2184 struct nft_ctx ctx;
2185 char name[IFNAMSIZ];
2186 unsigned int size;
2187 bool create;
2188 u32 ktype, klen, dlen, dtype, flags;
2189 int err;
2190
2191 if (nla[NFTA_SET_TABLE] == NULL ||
2192 nla[NFTA_SET_NAME] == NULL ||
2193 nla[NFTA_SET_KEY_LEN] == NULL)
2194 return -EINVAL;
2195
2196 ktype = NFT_DATA_VALUE;
2197 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2198 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2199 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2200 return -EINVAL;
2201 }
2202
2203 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2204 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
2205 return -EINVAL;
2206
2207 flags = 0;
2208 if (nla[NFTA_SET_FLAGS] != NULL) {
2209 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2210 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2211 NFT_SET_INTERVAL | NFT_SET_MAP))
2212 return -EINVAL;
2213 }
2214
2215 dtype = 0;
2216 dlen = 0;
2217 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2218 if (!(flags & NFT_SET_MAP))
2219 return -EINVAL;
2220
2221 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2222 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2223 dtype != NFT_DATA_VERDICT)
2224 return -EINVAL;
2225
2226 if (dtype != NFT_DATA_VERDICT) {
2227 if (nla[NFTA_SET_DATA_LEN] == NULL)
2228 return -EINVAL;
2229 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2230 if (dlen == 0 ||
2231 dlen > FIELD_SIZEOF(struct nft_data, data))
2232 return -EINVAL;
2233 } else
2234 dlen = sizeof(struct nft_data);
2235 } else if (flags & NFT_SET_MAP)
2236 return -EINVAL;
2237
2238 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2239
2240 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
2241 if (IS_ERR(afi))
2242 return PTR_ERR(afi);
2243
2244 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
2245 if (IS_ERR(table))
2246 return PTR_ERR(table);
2247
2248 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
2249
2250 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2251 if (IS_ERR(set)) {
2252 if (PTR_ERR(set) != -ENOENT)
2253 return PTR_ERR(set);
2254 set = NULL;
2255 }
2256
2257 if (set != NULL) {
2258 if (nlh->nlmsg_flags & NLM_F_EXCL)
2259 return -EEXIST;
2260 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2261 return -EOPNOTSUPP;
2262 return 0;
2263 }
2264
2265 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2266 return -ENOENT;
2267
2268 ops = nft_select_set_ops(nla);
2269 if (IS_ERR(ops))
2270 return PTR_ERR(ops);
2271
2272 size = 0;
2273 if (ops->privsize != NULL)
2274 size = ops->privsize(nla);
2275
2276 err = -ENOMEM;
2277 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2278 if (set == NULL)
2279 goto err1;
2280
2281 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2282 err = nf_tables_set_alloc_name(&ctx, set, name);
2283 if (err < 0)
2284 goto err2;
2285
2286 INIT_LIST_HEAD(&set->bindings);
2287 set->ops = ops;
2288 set->ktype = ktype;
2289 set->klen = klen;
2290 set->dtype = dtype;
2291 set->dlen = dlen;
2292 set->flags = flags;
2293
2294 err = ops->init(set, nla);
2295 if (err < 0)
2296 goto err2;
2297
2298 list_add_tail(&set->list, &table->sets);
2299 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2300 return 0;
2301
2302err2:
2303 kfree(set);
2304err1:
2305 module_put(ops->owner);
2306 return err;
2307}
2308
2309static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2310{
2311 list_del(&set->list);
2312 if (!(set->flags & NFT_SET_ANONYMOUS))
2313 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
2314
2315 set->ops->destroy(set);
2316 module_put(set->ops->owner);
2317 kfree(set);
2318}
2319
2320static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2321 const struct nlmsghdr *nlh,
2322 const struct nlattr * const nla[])
2323{
2324 struct nft_set *set;
2325 struct nft_ctx ctx;
2326 int err;
2327
2328 if (nla[NFTA_SET_TABLE] == NULL)
2329 return -EINVAL;
2330
2331 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2332 if (err < 0)
2333 return err;
2334
2335 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2336 if (IS_ERR(set))
2337 return PTR_ERR(set);
2338 if (!list_empty(&set->bindings))
2339 return -EBUSY;
2340
2341 nf_tables_set_destroy(&ctx, set);
2342 return 0;
2343}
2344
2345static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2346 const struct nft_set *set,
2347 const struct nft_set_iter *iter,
2348 const struct nft_set_elem *elem)
2349{
2350 enum nft_registers dreg;
2351
2352 dreg = nft_type_to_reg(set->dtype);
2353 return nft_validate_data_load(ctx, dreg, &elem->data, set->dtype);
2354}
2355
2356int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2357 struct nft_set_binding *binding)
2358{
2359 struct nft_set_binding *i;
2360 struct nft_set_iter iter;
2361
2362 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2363 return -EBUSY;
2364
2365 if (set->flags & NFT_SET_MAP) {
2366 /* If the set is already bound to the same chain all
2367 * jumps are already validated for that chain.
2368 */
2369 list_for_each_entry(i, &set->bindings, list) {
2370 if (i->chain == binding->chain)
2371 goto bind;
2372 }
2373
2374 iter.skip = 0;
2375 iter.count = 0;
2376 iter.err = 0;
2377 iter.fn = nf_tables_bind_check_setelem;
2378
2379 set->ops->walk(ctx, set, &iter);
2380 if (iter.err < 0) {
2381 /* Destroy anonymous sets if binding fails */
2382 if (set->flags & NFT_SET_ANONYMOUS)
2383 nf_tables_set_destroy(ctx, set);
2384
2385 return iter.err;
2386 }
2387 }
2388bind:
2389 binding->chain = ctx->chain;
2390 list_add_tail(&binding->list, &set->bindings);
2391 return 0;
2392}
2393
2394void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2395 struct nft_set_binding *binding)
2396{
2397 list_del(&binding->list);
2398
2399 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2400 nf_tables_set_destroy(ctx, set);
2401}
2402
2403/*
2404 * Set elements
2405 */
2406
2407static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2408 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2409 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2410 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2411};
2412
2413static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2414 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2415 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2416 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2417};
2418
2419static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2420 const struct sk_buff *skb,
2421 const struct nlmsghdr *nlh,
2422 const struct nlattr * const nla[])
2423{
2424 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2425 const struct nft_af_info *afi;
2426 const struct nft_table *table;
2427 struct net *net = sock_net(skb->sk);
2428
2429 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
2430 if (IS_ERR(afi))
2431 return PTR_ERR(afi);
2432
2433 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
2434 if (IS_ERR(table))
2435 return PTR_ERR(table);
2436
2437 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
2438 return 0;
2439}
2440
2441static int nf_tables_fill_setelem(struct sk_buff *skb,
2442 const struct nft_set *set,
2443 const struct nft_set_elem *elem)
2444{
2445 unsigned char *b = skb_tail_pointer(skb);
2446 struct nlattr *nest;
2447
2448 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2449 if (nest == NULL)
2450 goto nla_put_failure;
2451
2452 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2453 set->klen) < 0)
2454 goto nla_put_failure;
2455
2456 if (set->flags & NFT_SET_MAP &&
2457 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2458 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2459 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2460 set->dlen) < 0)
2461 goto nla_put_failure;
2462
2463 if (elem->flags != 0)
2464 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2465 goto nla_put_failure;
2466
2467 nla_nest_end(skb, nest);
2468 return 0;
2469
2470nla_put_failure:
2471 nlmsg_trim(skb, b);
2472 return -EMSGSIZE;
2473}
2474
2475struct nft_set_dump_args {
2476 const struct netlink_callback *cb;
2477 struct nft_set_iter iter;
2478 struct sk_buff *skb;
2479};
2480
2481static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2482 const struct nft_set *set,
2483 const struct nft_set_iter *iter,
2484 const struct nft_set_elem *elem)
2485{
2486 struct nft_set_dump_args *args;
2487
2488 args = container_of(iter, struct nft_set_dump_args, iter);
2489 return nf_tables_fill_setelem(args->skb, set, elem);
2490}
2491
2492static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2493{
2494 const struct nft_set *set;
2495 struct nft_set_dump_args args;
2496 struct nft_ctx ctx;
2497 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2498 struct nfgenmsg *nfmsg;
2499 struct nlmsghdr *nlh;
2500 struct nlattr *nest;
2501 u32 portid, seq;
2502 int event, err;
2503
2504 nfmsg = nlmsg_data(cb->nlh);
2505 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX,
2506 nft_set_elem_list_policy);
2507 if (err < 0)
2508 return err;
2509
2510 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2511 if (err < 0)
2512 return err;
2513
2514 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2515 if (IS_ERR(set))
2516 return PTR_ERR(set);
2517
2518 event = NFT_MSG_NEWSETELEM;
2519 event |= NFNL_SUBSYS_NFTABLES << 8;
2520 portid = NETLINK_CB(cb->skb).portid;
2521 seq = cb->nlh->nlmsg_seq;
2522
2523 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2524 NLM_F_MULTI);
2525 if (nlh == NULL)
2526 goto nla_put_failure;
2527
2528 nfmsg = nlmsg_data(nlh);
2529 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2530 nfmsg->version = NFNETLINK_V0;
2531 nfmsg->res_id = 0;
2532
2533 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2534 goto nla_put_failure;
2535 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2536 goto nla_put_failure;
2537
2538 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2539 if (nest == NULL)
2540 goto nla_put_failure;
2541
2542 args.cb = cb;
2543 args.skb = skb;
2544 args.iter.skip = cb->args[0];
2545 args.iter.count = 0;
2546 args.iter.err = 0;
2547 args.iter.fn = nf_tables_dump_setelem;
2548 set->ops->walk(&ctx, set, &args.iter);
2549
2550 nla_nest_end(skb, nest);
2551 nlmsg_end(skb, nlh);
2552
2553 if (args.iter.err && args.iter.err != -EMSGSIZE)
2554 return args.iter.err;
2555 if (args.iter.count == cb->args[0])
2556 return 0;
2557
2558 cb->args[0] = args.iter.count;
2559 return skb->len;
2560
2561nla_put_failure:
2562 return -ENOSPC;
2563}
2564
2565static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2566 const struct nlmsghdr *nlh,
2567 const struct nlattr * const nla[])
2568{
2569 const struct nft_set *set;
2570 struct nft_ctx ctx;
2571 int err;
2572
2573 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2574 if (err < 0)
2575 return err;
2576
2577 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2578 if (IS_ERR(set))
2579 return PTR_ERR(set);
2580
2581 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2582 struct netlink_dump_control c = {
2583 .dump = nf_tables_dump_set,
2584 };
2585 return netlink_dump_start(nlsk, skb, nlh, &c);
2586 }
2587 return -EOPNOTSUPP;
2588}
2589
2590static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2591 const struct nlattr *attr)
2592{
2593 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2594 struct nft_data_desc d1, d2;
2595 struct nft_set_elem elem;
2596 struct nft_set_binding *binding;
2597 enum nft_registers dreg;
2598 int err;
2599
2600 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2601 nft_set_elem_policy);
2602 if (err < 0)
2603 return err;
2604
2605 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2606 return -EINVAL;
2607
2608 elem.flags = 0;
2609 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2610 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2611 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2612 return -EINVAL;
2613 }
2614
2615 if (set->flags & NFT_SET_MAP) {
2616 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2617 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2618 return -EINVAL;
2619 } else {
2620 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2621 return -EINVAL;
2622 }
2623
2624 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2625 if (err < 0)
2626 goto err1;
2627 err = -EINVAL;
2628 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2629 goto err2;
2630
2631 err = -EEXIST;
2632 if (set->ops->get(set, &elem) == 0)
2633 goto err2;
2634
2635 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2636 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2637 if (err < 0)
2638 goto err2;
2639
2640 err = -EINVAL;
2641 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2642 goto err3;
2643
2644 dreg = nft_type_to_reg(set->dtype);
2645 list_for_each_entry(binding, &set->bindings, list) {
2646 struct nft_ctx bind_ctx = {
2647 .afi = ctx->afi,
2648 .table = ctx->table,
2649 .chain = binding->chain,
2650 };
2651
2652 err = nft_validate_data_load(&bind_ctx, dreg,
2653 &elem.data, d2.type);
2654 if (err < 0)
2655 goto err3;
2656 }
2657 }
2658
2659 err = set->ops->insert(set, &elem);
2660 if (err < 0)
2661 goto err3;
2662
2663 return 0;
2664
2665err3:
2666 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2667 nft_data_uninit(&elem.data, d2.type);
2668err2:
2669 nft_data_uninit(&elem.key, d1.type);
2670err1:
2671 return err;
2672}
2673
2674static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2675 const struct nlmsghdr *nlh,
2676 const struct nlattr * const nla[])
2677{
2678 const struct nlattr *attr;
2679 struct nft_set *set;
2680 struct nft_ctx ctx;
2681 int rem, err;
2682
2683 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2684 if (err < 0)
2685 return err;
2686
2687 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2688 if (IS_ERR(set))
2689 return PTR_ERR(set);
2690 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2691 return -EBUSY;
2692
2693 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2694 err = nft_add_set_elem(&ctx, set, attr);
2695 if (err < 0)
2696 return err;
2697 }
2698 return 0;
2699}
2700
2701static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2702 const struct nlattr *attr)
2703{
2704 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2705 struct nft_data_desc desc;
2706 struct nft_set_elem elem;
2707 int err;
2708
2709 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2710 nft_set_elem_policy);
2711 if (err < 0)
2712 goto err1;
2713
2714 err = -EINVAL;
2715 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2716 goto err1;
2717
2718 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2719 if (err < 0)
2720 goto err1;
2721
2722 err = -EINVAL;
2723 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2724 goto err2;
2725
2726 err = set->ops->get(set, &elem);
2727 if (err < 0)
2728 goto err2;
2729
2730 set->ops->remove(set, &elem);
2731
2732 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2733 if (set->flags & NFT_SET_MAP)
2734 nft_data_uninit(&elem.data, set->dtype);
2735
2736err2:
2737 nft_data_uninit(&elem.key, desc.type);
2738err1:
2739 return err;
2740}
2741
2742static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2743 const struct nlmsghdr *nlh,
2744 const struct nlattr * const nla[])
2745{
2746 const struct nlattr *attr;
2747 struct nft_set *set;
2748 struct nft_ctx ctx;
2749 int rem, err;
2750
2751 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2752 if (err < 0)
2753 return err;
2754
2755 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2756 if (IS_ERR(set))
2757 return PTR_ERR(set);
2758 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2759 return -EBUSY;
2760
2761 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2762 err = nft_del_setelem(&ctx, set, attr);
2763 if (err < 0)
2764 return err;
2765 }
2766 return 0;
2767}
2768
2769static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
2770 [NFT_MSG_NEWTABLE] = {
2771 .call = nf_tables_newtable,
2772 .attr_count = NFTA_TABLE_MAX,
2773 .policy = nft_table_policy,
2774 },
2775 [NFT_MSG_GETTABLE] = {
2776 .call = nf_tables_gettable,
2777 .attr_count = NFTA_TABLE_MAX,
2778 .policy = nft_table_policy,
2779 },
2780 [NFT_MSG_DELTABLE] = {
2781 .call = nf_tables_deltable,
2782 .attr_count = NFTA_TABLE_MAX,
2783 .policy = nft_table_policy,
2784 },
2785 [NFT_MSG_NEWCHAIN] = {
2786 .call = nf_tables_newchain,
2787 .attr_count = NFTA_CHAIN_MAX,
2788 .policy = nft_chain_policy,
2789 },
2790 [NFT_MSG_GETCHAIN] = {
2791 .call = nf_tables_getchain,
2792 .attr_count = NFTA_CHAIN_MAX,
2793 .policy = nft_chain_policy,
2794 },
2795 [NFT_MSG_DELCHAIN] = {
2796 .call = nf_tables_delchain,
2797 .attr_count = NFTA_CHAIN_MAX,
2798 .policy = nft_chain_policy,
2799 },
2800 [NFT_MSG_NEWRULE] = {
2801 .call_batch = nf_tables_newrule,
2802 .attr_count = NFTA_RULE_MAX,
2803 .policy = nft_rule_policy,
2804 },
2805 [NFT_MSG_GETRULE] = {
2806 .call = nf_tables_getrule,
2807 .attr_count = NFTA_RULE_MAX,
2808 .policy = nft_rule_policy,
2809 },
2810 [NFT_MSG_DELRULE] = {
2811 .call_batch = nf_tables_delrule,
2812 .attr_count = NFTA_RULE_MAX,
2813 .policy = nft_rule_policy,
2814 },
2815 [NFT_MSG_NEWSET] = {
2816 .call = nf_tables_newset,
2817 .attr_count = NFTA_SET_MAX,
2818 .policy = nft_set_policy,
2819 },
2820 [NFT_MSG_GETSET] = {
2821 .call = nf_tables_getset,
2822 .attr_count = NFTA_SET_MAX,
2823 .policy = nft_set_policy,
2824 },
2825 [NFT_MSG_DELSET] = {
2826 .call = nf_tables_delset,
2827 .attr_count = NFTA_SET_MAX,
2828 .policy = nft_set_policy,
2829 },
2830 [NFT_MSG_NEWSETELEM] = {
2831 .call = nf_tables_newsetelem,
2832 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2833 .policy = nft_set_elem_list_policy,
2834 },
2835 [NFT_MSG_GETSETELEM] = {
2836 .call = nf_tables_getsetelem,
2837 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2838 .policy = nft_set_elem_list_policy,
2839 },
2840 [NFT_MSG_DELSETELEM] = {
2841 .call = nf_tables_delsetelem,
2842 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2843 .policy = nft_set_elem_list_policy,
2844 },
2845};
2846
2847static const struct nfnetlink_subsystem nf_tables_subsys = {
2848 .name = "nf_tables",
2849 .subsys_id = NFNL_SUBSYS_NFTABLES,
2850 .cb_count = NFT_MSG_MAX,
2851 .cb = nf_tables_cb,
2852 .commit = nf_tables_commit,
2853 .abort = nf_tables_abort,
2854};
2855
2856/*
2857 * Loop detection - walk through the ruleset beginning at the destination chain
2858 * of a new jump until either the source chain is reached (loop) or all
2859 * reachable chains have been traversed.
2860 *
2861 * The loop check is performed whenever a new jump verdict is added to an
2862 * expression or verdict map or a verdict map is bound to a new chain.
2863 */
2864
2865static int nf_tables_check_loops(const struct nft_ctx *ctx,
2866 const struct nft_chain *chain);
2867
2868static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2869 const struct nft_set *set,
2870 const struct nft_set_iter *iter,
2871 const struct nft_set_elem *elem)
2872{
2873 switch (elem->data.verdict) {
2874 case NFT_JUMP:
2875 case NFT_GOTO:
2876 return nf_tables_check_loops(ctx, elem->data.chain);
2877 default:
2878 return 0;
2879 }
2880}
2881
2882static int nf_tables_check_loops(const struct nft_ctx *ctx,
2883 const struct nft_chain *chain)
2884{
2885 const struct nft_rule *rule;
2886 const struct nft_expr *expr, *last;
2887 const struct nft_set *set;
2888 struct nft_set_binding *binding;
2889 struct nft_set_iter iter;
2890
2891 if (ctx->chain == chain)
2892 return -ELOOP;
2893
2894 list_for_each_entry(rule, &chain->rules, list) {
2895 nft_rule_for_each_expr(expr, last, rule) {
2896 const struct nft_data *data = NULL;
2897 int err;
2898
2899 if (!expr->ops->validate)
2900 continue;
2901
2902 err = expr->ops->validate(ctx, expr, &data);
2903 if (err < 0)
2904 return err;
2905
2906 if (data == NULL)
2907 continue;
2908
2909 switch (data->verdict) {
2910 case NFT_JUMP:
2911 case NFT_GOTO:
2912 err = nf_tables_check_loops(ctx, data->chain);
2913 if (err < 0)
2914 return err;
2915 default:
2916 break;
2917 }
2918 }
2919 }
2920
2921 list_for_each_entry(set, &ctx->table->sets, list) {
2922 if (!(set->flags & NFT_SET_MAP) ||
2923 set->dtype != NFT_DATA_VERDICT)
2924 continue;
2925
2926 list_for_each_entry(binding, &set->bindings, list) {
2927 if (binding->chain != chain)
2928 continue;
2929
2930 iter.skip = 0;
2931 iter.count = 0;
2932 iter.err = 0;
2933 iter.fn = nf_tables_loop_check_setelem;
2934
2935 set->ops->walk(ctx, set, &iter);
2936 if (iter.err < 0)
2937 return iter.err;
2938 }
2939 }
2940
2941 return 0;
2942}
2943
2944/**
2945 * nft_validate_input_register - validate an expressions' input register
2946 *
2947 * @reg: the register number
2948 *
2949 * Validate that the input register is one of the general purpose
2950 * registers.
2951 */
2952int nft_validate_input_register(enum nft_registers reg)
2953{
2954 if (reg <= NFT_REG_VERDICT)
2955 return -EINVAL;
2956 if (reg > NFT_REG_MAX)
2957 return -ERANGE;
2958 return 0;
2959}
2960EXPORT_SYMBOL_GPL(nft_validate_input_register);
2961
2962/**
2963 * nft_validate_output_register - validate an expressions' output register
2964 *
2965 * @reg: the register number
2966 *
2967 * Validate that the output register is one of the general purpose
2968 * registers or the verdict register.
2969 */
2970int nft_validate_output_register(enum nft_registers reg)
2971{
2972 if (reg < NFT_REG_VERDICT)
2973 return -EINVAL;
2974 if (reg > NFT_REG_MAX)
2975 return -ERANGE;
2976 return 0;
2977}
2978EXPORT_SYMBOL_GPL(nft_validate_output_register);
2979
2980/**
2981 * nft_validate_data_load - validate an expressions' data load
2982 *
2983 * @ctx: context of the expression performing the load
2984 * @reg: the destination register number
2985 * @data: the data to load
2986 * @type: the data type
2987 *
2988 * Validate that a data load uses the appropriate data type for
2989 * the destination register. A value of NULL for the data means
2990 * that its runtime gathered data, which is always of type
2991 * NFT_DATA_VALUE.
2992 */
2993int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
2994 const struct nft_data *data,
2995 enum nft_data_types type)
2996{
2997 int err;
2998
2999 switch (reg) {
3000 case NFT_REG_VERDICT:
3001 if (data == NULL || type != NFT_DATA_VERDICT)
3002 return -EINVAL;
3003
3004 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3005 err = nf_tables_check_loops(ctx, data->chain);
3006 if (err < 0)
3007 return err;
3008
3009 if (ctx->chain->level + 1 > data->chain->level) {
3010 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3011 return -EMLINK;
3012 data->chain->level = ctx->chain->level + 1;
3013 }
3014 }
3015
3016 return 0;
3017 default:
3018 if (data != NULL && type != NFT_DATA_VALUE)
3019 return -EINVAL;
3020 return 0;
3021 }
3022}
3023EXPORT_SYMBOL_GPL(nft_validate_data_load);
3024
3025static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3026 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3027 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3028 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3029};
3030
3031static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3032 struct nft_data_desc *desc, const struct nlattr *nla)
3033{
3034 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3035 struct nft_chain *chain;
3036 int err;
3037
3038 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3039 if (err < 0)
3040 return err;
3041
3042 if (!tb[NFTA_VERDICT_CODE])
3043 return -EINVAL;
3044 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3045
3046 switch (data->verdict) {
3047 case NF_ACCEPT:
3048 case NF_DROP:
3049 case NF_QUEUE:
3050 case NFT_CONTINUE:
3051 case NFT_BREAK:
3052 case NFT_RETURN:
3053 desc->len = sizeof(data->verdict);
3054 break;
3055 case NFT_JUMP:
3056 case NFT_GOTO:
3057 if (!tb[NFTA_VERDICT_CHAIN])
3058 return -EINVAL;
3059 chain = nf_tables_chain_lookup(ctx->table,
3060 tb[NFTA_VERDICT_CHAIN]);
3061 if (IS_ERR(chain))
3062 return PTR_ERR(chain);
3063 if (chain->flags & NFT_BASE_CHAIN)
3064 return -EOPNOTSUPP;
3065
3066 chain->use++;
3067 data->chain = chain;
3068 desc->len = sizeof(data);
3069 break;
3070 default:
3071 return -EINVAL;
3072 }
3073
3074 desc->type = NFT_DATA_VERDICT;
3075 return 0;
3076}
3077
3078static void nft_verdict_uninit(const struct nft_data *data)
3079{
3080 switch (data->verdict) {
3081 case NFT_JUMP:
3082 case NFT_GOTO:
3083 data->chain->use--;
3084 break;
3085 }
3086}
3087
3088static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3089{
3090 struct nlattr *nest;
3091
3092 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3093 if (!nest)
3094 goto nla_put_failure;
3095
3096 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3097 goto nla_put_failure;
3098
3099 switch (data->verdict) {
3100 case NFT_JUMP:
3101 case NFT_GOTO:
3102 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3103 goto nla_put_failure;
3104 }
3105 nla_nest_end(skb, nest);
3106 return 0;
3107
3108nla_put_failure:
3109 return -1;
3110}
3111
3112static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3113 struct nft_data_desc *desc, const struct nlattr *nla)
3114{
3115 unsigned int len;
3116
3117 len = nla_len(nla);
3118 if (len == 0)
3119 return -EINVAL;
3120 if (len > sizeof(data->data))
3121 return -EOVERFLOW;
3122
3123 nla_memcpy(data->data, nla, sizeof(data->data));
3124 desc->type = NFT_DATA_VALUE;
3125 desc->len = len;
3126 return 0;
3127}
3128
3129static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3130 unsigned int len)
3131{
3132 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3133}
3134
3135static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3136 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3137 .len = FIELD_SIZEOF(struct nft_data, data) },
3138 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3139};
3140
3141/**
3142 * nft_data_init - parse nf_tables data netlink attributes
3143 *
3144 * @ctx: context of the expression using the data
3145 * @data: destination struct nft_data
3146 * @desc: data description
3147 * @nla: netlink attribute containing data
3148 *
3149 * Parse the netlink data attributes and initialize a struct nft_data.
3150 * The type and length of data are returned in the data description.
3151 *
3152 * The caller can indicate that it only wants to accept data of type
3153 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3154 */
3155int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3156 struct nft_data_desc *desc, const struct nlattr *nla)
3157{
3158 struct nlattr *tb[NFTA_DATA_MAX + 1];
3159 int err;
3160
3161 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3162 if (err < 0)
3163 return err;
3164
3165 if (tb[NFTA_DATA_VALUE])
3166 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3167 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3168 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3169 return -EINVAL;
3170}
3171EXPORT_SYMBOL_GPL(nft_data_init);
3172
3173/**
3174 * nft_data_uninit - release a nft_data item
3175 *
3176 * @data: struct nft_data to release
3177 * @type: type of data
3178 *
3179 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3180 * all others need to be released by calling this function.
3181 */
3182void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3183{
3184 switch (type) {
3185 case NFT_DATA_VALUE:
3186 return;
3187 case NFT_DATA_VERDICT:
3188 return nft_verdict_uninit(data);
3189 default:
3190 WARN_ON(1);
3191 }
3192}
3193EXPORT_SYMBOL_GPL(nft_data_uninit);
3194
3195int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3196 enum nft_data_types type, unsigned int len)
3197{
3198 struct nlattr *nest;
3199 int err;
3200
3201 nest = nla_nest_start(skb, attr);
3202 if (nest == NULL)
3203 return -1;
3204
3205 switch (type) {
3206 case NFT_DATA_VALUE:
3207 err = nft_value_dump(skb, data, len);
3208 break;
3209 case NFT_DATA_VERDICT:
3210 err = nft_verdict_dump(skb, data);
3211 break;
3212 default:
3213 err = -EINVAL;
3214 WARN_ON(1);
3215 }
3216
3217 nla_nest_end(skb, nest);
3218 return err;
3219}
3220EXPORT_SYMBOL_GPL(nft_data_dump);
3221
3222static int nf_tables_init_net(struct net *net)
3223{
3224 INIT_LIST_HEAD(&net->nft.af_info);
3225 INIT_LIST_HEAD(&net->nft.commit_list);
3226 return 0;
3227}
3228
3229static struct pernet_operations nf_tables_net_ops = {
3230 .init = nf_tables_init_net,
3231};
3232
3233static int __init nf_tables_module_init(void)
3234{
3235 int err;
3236
3237 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3238 GFP_KERNEL);
3239 if (info == NULL) {
3240 err = -ENOMEM;
3241 goto err1;
3242 }
3243
3244 err = nf_tables_core_module_init();
3245 if (err < 0)
3246 goto err2;
3247
3248 err = nfnetlink_subsys_register(&nf_tables_subsys);
3249 if (err < 0)
3250 goto err3;
3251
3252 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
3253 return register_pernet_subsys(&nf_tables_net_ops);
3254err3:
3255 nf_tables_core_module_exit();
3256err2:
3257 kfree(info);
3258err1:
3259 return err;
3260}
3261
3262static void __exit nf_tables_module_exit(void)
3263{
3264 unregister_pernet_subsys(&nf_tables_net_ops);
3265 nfnetlink_subsys_unregister(&nf_tables_subsys);
3266 nf_tables_core_module_exit();
3267 kfree(info);
3268}
3269
3270module_init(nf_tables_module_init);
3271module_exit(nf_tables_module_exit);
3272
3273MODULE_LICENSE("GPL");
3274MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3275MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
new file mode 100644
index 000000000000..cb9e685caae1
--- /dev/null
+++ b/net/netfilter/nf_tables_core.c
@@ -0,0 +1,270 @@
1/*
2 * Copyright (c) 2008 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/rculist.h>
15#include <linux/skbuff.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nfnetlink.h>
19#include <linux/netfilter/nf_tables.h>
20#include <net/netfilter/nf_tables_core.h>
21#include <net/netfilter/nf_tables.h>
22#include <net/netfilter/nf_log.h>
23
24static void nft_cmp_fast_eval(const struct nft_expr *expr,
25 struct nft_data data[NFT_REG_MAX + 1])
26{
27 const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
28 u32 mask;
29
30 mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - priv->len);
31 if ((data[priv->sreg].data[0] & mask) == priv->data)
32 return;
33 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
34}
35
36static bool nft_payload_fast_eval(const struct nft_expr *expr,
37 struct nft_data data[NFT_REG_MAX + 1],
38 const struct nft_pktinfo *pkt)
39{
40 const struct nft_payload *priv = nft_expr_priv(expr);
41 const struct sk_buff *skb = pkt->skb;
42 struct nft_data *dest = &data[priv->dreg];
43 unsigned char *ptr;
44
45 if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
46 ptr = skb_network_header(skb);
47 else
48 ptr = skb_network_header(skb) + pkt->xt.thoff;
49
50 ptr += priv->offset;
51
52 if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
53 return false;
54
55 if (priv->len == 2)
56 *(u16 *)dest->data = *(u16 *)ptr;
57 else if (priv->len == 4)
58 *(u32 *)dest->data = *(u32 *)ptr;
59 else
60 *(u8 *)dest->data = *(u8 *)ptr;
61 return true;
62}
63
64struct nft_jumpstack {
65 const struct nft_chain *chain;
66 const struct nft_rule *rule;
67 int rulenum;
68};
69
70static inline void
71nft_chain_stats(const struct nft_chain *this, const struct nft_pktinfo *pkt,
72 struct nft_jumpstack *jumpstack, unsigned int stackptr)
73{
74 struct nft_stats __percpu *stats;
75 const struct nft_chain *chain = stackptr ? jumpstack[0].chain : this;
76
77 rcu_read_lock_bh();
78 stats = rcu_dereference(nft_base_chain(chain)->stats);
79 __this_cpu_inc(stats->pkts);
80 __this_cpu_add(stats->bytes, pkt->skb->len);
81 rcu_read_unlock_bh();
82}
83
84enum nft_trace {
85 NFT_TRACE_RULE,
86 NFT_TRACE_RETURN,
87 NFT_TRACE_POLICY,
88};
89
90static const char *const comments[] = {
91 [NFT_TRACE_RULE] = "rule",
92 [NFT_TRACE_RETURN] = "return",
93 [NFT_TRACE_POLICY] = "policy",
94};
95
96static struct nf_loginfo trace_loginfo = {
97 .type = NF_LOG_TYPE_LOG,
98 .u = {
99 .log = {
100 .level = 4,
101 .logflags = NF_LOG_MASK,
102 },
103 },
104};
105
106static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
107 const struct nft_chain *chain,
108 int rulenum, enum nft_trace type)
109{
110 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
111
112 nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in,
113 pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
114 chain->table->name, chain->name, comments[type],
115 rulenum);
116}
117
118unsigned int
119nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
120{
121 const struct nft_chain *chain = ops->priv;
122 const struct nft_rule *rule;
123 const struct nft_expr *expr, *last;
124 struct nft_data data[NFT_REG_MAX + 1];
125 unsigned int stackptr = 0;
126 struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
127 int rulenum = 0;
128 /*
129 * Cache cursor to avoid problems in case that the cursor is updated
130 * while traversing the ruleset.
131 */
132 unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
133
134do_chain:
135 rule = list_entry(&chain->rules, struct nft_rule, list);
136next_rule:
137 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
138 list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
139
140 /* This rule is not active, skip. */
141 if (unlikely(rule->genmask & (1 << gencursor)))
142 continue;
143
144 rulenum++;
145
146 nft_rule_for_each_expr(expr, last, rule) {
147 if (expr->ops == &nft_cmp_fast_ops)
148 nft_cmp_fast_eval(expr, data);
149 else if (expr->ops != &nft_payload_fast_ops ||
150 !nft_payload_fast_eval(expr, data, pkt))
151 expr->ops->eval(expr, data, pkt);
152
153 if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
154 break;
155 }
156
157 switch (data[NFT_REG_VERDICT].verdict) {
158 case NFT_BREAK:
159 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
160 /* fall through */
161 case NFT_CONTINUE:
162 continue;
163 }
164 break;
165 }
166
167 switch (data[NFT_REG_VERDICT].verdict) {
168 case NF_ACCEPT:
169 case NF_DROP:
170 case NF_QUEUE:
171 if (unlikely(pkt->skb->nf_trace))
172 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
173
174 return data[NFT_REG_VERDICT].verdict;
175 case NFT_JUMP:
176 if (unlikely(pkt->skb->nf_trace))
177 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
178
179 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
180 jumpstack[stackptr].chain = chain;
181 jumpstack[stackptr].rule = rule;
182 jumpstack[stackptr].rulenum = rulenum;
183 stackptr++;
184 /* fall through */
185 case NFT_GOTO:
186 chain = data[NFT_REG_VERDICT].chain;
187 goto do_chain;
188 case NFT_RETURN:
189 if (unlikely(pkt->skb->nf_trace))
190 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
191
192 /* fall through */
193 case NFT_CONTINUE:
194 break;
195 default:
196 WARN_ON(1);
197 }
198
199 if (stackptr > 0) {
200 if (unlikely(pkt->skb->nf_trace))
201 nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
202
203 stackptr--;
204 chain = jumpstack[stackptr].chain;
205 rule = jumpstack[stackptr].rule;
206 rulenum = jumpstack[stackptr].rulenum;
207 goto next_rule;
208 }
209 nft_chain_stats(chain, pkt, jumpstack, stackptr);
210
211 if (unlikely(pkt->skb->nf_trace))
212 nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);
213
214 return nft_base_chain(chain)->policy;
215}
216EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo);
217
218int __init nf_tables_core_module_init(void)
219{
220 int err;
221
222 err = nft_immediate_module_init();
223 if (err < 0)
224 goto err1;
225
226 err = nft_cmp_module_init();
227 if (err < 0)
228 goto err2;
229
230 err = nft_lookup_module_init();
231 if (err < 0)
232 goto err3;
233
234 err = nft_bitwise_module_init();
235 if (err < 0)
236 goto err4;
237
238 err = nft_byteorder_module_init();
239 if (err < 0)
240 goto err5;
241
242 err = nft_payload_module_init();
243 if (err < 0)
244 goto err6;
245
246 return 0;
247
248err6:
249 nft_byteorder_module_exit();
250err5:
251 nft_bitwise_module_exit();
252err4:
253 nft_lookup_module_exit();
254err3:
255 nft_cmp_module_exit();
256err2:
257 nft_immediate_module_exit();
258err1:
259 return err;
260}
261
262void nf_tables_core_module_exit(void)
263{
264 nft_payload_module_exit();
265 nft_byteorder_module_exit();
266 nft_bitwise_module_exit();
267 nft_lookup_module_exit();
268 nft_cmp_module_exit();
269 nft_immediate_module_exit();
270}
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 572d87dc116f..027f16af51a0 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -147,9 +147,6 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
147 const struct nfnetlink_subsystem *ss; 147 const struct nfnetlink_subsystem *ss;
148 int type, err; 148 int type, err;
149 149
150 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
151 return -EPERM;
152
153 /* All the messages must at least contain nfgenmsg */ 150 /* All the messages must at least contain nfgenmsg */
154 if (nlmsg_len(nlh) < sizeof(struct nfgenmsg)) 151 if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
155 return 0; 152 return 0;
@@ -217,9 +214,179 @@ replay:
217 } 214 }
218} 215}
219 216
217static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
218 u_int16_t subsys_id)
219{
220 struct sk_buff *nskb, *oskb = skb;
221 struct net *net = sock_net(skb->sk);
222 const struct nfnetlink_subsystem *ss;
223 const struct nfnl_callback *nc;
224 bool success = true, done = false;
225 int err;
226
227 if (subsys_id >= NFNL_SUBSYS_COUNT)
228 return netlink_ack(skb, nlh, -EINVAL);
229replay:
230 nskb = netlink_skb_clone(oskb, GFP_KERNEL);
231 if (!nskb)
232 return netlink_ack(oskb, nlh, -ENOMEM);
233
234 nskb->sk = oskb->sk;
235 skb = nskb;
236
237 nfnl_lock(subsys_id);
238 ss = rcu_dereference_protected(table[subsys_id].subsys,
239 lockdep_is_held(&table[subsys_id].mutex));
240 if (!ss) {
241#ifdef CONFIG_MODULES
242 nfnl_unlock(subsys_id);
243 request_module("nfnetlink-subsys-%d", subsys_id);
244 nfnl_lock(subsys_id);
245 ss = rcu_dereference_protected(table[subsys_id].subsys,
246 lockdep_is_held(&table[subsys_id].mutex));
247 if (!ss)
248#endif
249 {
250 nfnl_unlock(subsys_id);
251 kfree_skb(nskb);
252 return netlink_ack(skb, nlh, -EOPNOTSUPP);
253 }
254 }
255
256 if (!ss->commit || !ss->abort) {
257 nfnl_unlock(subsys_id);
258 kfree_skb(nskb);
259 return netlink_ack(skb, nlh, -EOPNOTSUPP);
260 }
261
262 while (skb->len >= nlmsg_total_size(0)) {
263 int msglen, type;
264
265 nlh = nlmsg_hdr(skb);
266 err = 0;
267
268 if (nlh->nlmsg_len < NLMSG_HDRLEN) {
269 err = -EINVAL;
270 goto ack;
271 }
272
273 /* Only requests are handled by the kernel */
274 if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
275 err = -EINVAL;
276 goto ack;
277 }
278
279 type = nlh->nlmsg_type;
280 if (type == NFNL_MSG_BATCH_BEGIN) {
281 /* Malformed: Batch begin twice */
282 success = false;
283 goto done;
284 } else if (type == NFNL_MSG_BATCH_END) {
285 done = true;
286 goto done;
287 } else if (type < NLMSG_MIN_TYPE) {
288 err = -EINVAL;
289 goto ack;
290 }
291
292 /* We only accept a batch with messages for the same
293 * subsystem.
294 */
295 if (NFNL_SUBSYS_ID(type) != subsys_id) {
296 err = -EINVAL;
297 goto ack;
298 }
299
300 nc = nfnetlink_find_client(type, ss);
301 if (!nc) {
302 err = -EINVAL;
303 goto ack;
304 }
305
306 {
307 int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
308 u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
309 struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
310 struct nlattr *attr = (void *)nlh + min_len;
311 int attrlen = nlh->nlmsg_len - min_len;
312
313 err = nla_parse(cda, ss->cb[cb_id].attr_count,
314 attr, attrlen, ss->cb[cb_id].policy);
315 if (err < 0)
316 goto ack;
317
318 if (nc->call_batch) {
319 err = nc->call_batch(net->nfnl, skb, nlh,
320 (const struct nlattr **)cda);
321 }
322
323 /* The lock was released to autoload some module, we
324 * have to abort and start from scratch using the
325 * original skb.
326 */
327 if (err == -EAGAIN) {
328 ss->abort(skb);
329 nfnl_unlock(subsys_id);
330 kfree_skb(nskb);
331 goto replay;
332 }
333 }
334ack:
335 if (nlh->nlmsg_flags & NLM_F_ACK || err) {
336 /* We don't stop processing the batch on errors, thus,
337 * userspace gets all the errors that the batch
338 * triggers.
339 */
340 netlink_ack(skb, nlh, err);
341 if (err)
342 success = false;
343 }
344
345 msglen = NLMSG_ALIGN(nlh->nlmsg_len);
346 if (msglen > skb->len)
347 msglen = skb->len;
348 skb_pull(skb, msglen);
349 }
350done:
351 if (success && done)
352 ss->commit(skb);
353 else
354 ss->abort(skb);
355
356 nfnl_unlock(subsys_id);
357 kfree_skb(nskb);
358}
359
220static void nfnetlink_rcv(struct sk_buff *skb) 360static void nfnetlink_rcv(struct sk_buff *skb)
221{ 361{
222 netlink_rcv_skb(skb, &nfnetlink_rcv_msg); 362 struct nlmsghdr *nlh = nlmsg_hdr(skb);
363 struct net *net = sock_net(skb->sk);
364 int msglen;
365
366 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
367 return netlink_ack(skb, nlh, -EPERM);
368
369 if (nlh->nlmsg_len < NLMSG_HDRLEN ||
370 skb->len < nlh->nlmsg_len)
371 return;
372
373 if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN) {
374 struct nfgenmsg *nfgenmsg;
375
376 msglen = NLMSG_ALIGN(nlh->nlmsg_len);
377 if (msglen > skb->len)
378 msglen = skb->len;
379
380 if (nlh->nlmsg_len < NLMSG_HDRLEN ||
381 skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
382 return;
383
384 nfgenmsg = nlmsg_data(nlh);
385 skb_pull(skb, msglen);
386 nfnetlink_rcv_batch(skb, nlh, nfgenmsg->res_id);
387 } else {
388 netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
389 }
223} 390}
224 391
225#ifdef CONFIG_MODULES 392#ifdef CONFIG_MODULES
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
new file mode 100644
index 000000000000..4fb6ee2c1106
--- /dev/null
+++ b/net/netfilter/nft_bitwise.c
@@ -0,0 +1,146 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_bitwise {
21 enum nft_registers sreg:8;
22 enum nft_registers dreg:8;
23 u8 len;
24 struct nft_data mask;
25 struct nft_data xor;
26};
27
28static void nft_bitwise_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 const struct nft_bitwise *priv = nft_expr_priv(expr);
33 const struct nft_data *src = &data[priv->sreg];
34 struct nft_data *dst = &data[priv->dreg];
35 unsigned int i;
36
37 for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) {
38 dst->data[i] = (src->data[i] & priv->mask.data[i]) ^
39 priv->xor.data[i];
40 }
41}
42
43static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
44 [NFTA_BITWISE_SREG] = { .type = NLA_U32 },
45 [NFTA_BITWISE_DREG] = { .type = NLA_U32 },
46 [NFTA_BITWISE_LEN] = { .type = NLA_U32 },
47 [NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
48 [NFTA_BITWISE_XOR] = { .type = NLA_NESTED },
49};
50
51static int nft_bitwise_init(const struct nft_ctx *ctx,
52 const struct nft_expr *expr,
53 const struct nlattr * const tb[])
54{
55 struct nft_bitwise *priv = nft_expr_priv(expr);
56 struct nft_data_desc d1, d2;
57 int err;
58
59 if (tb[NFTA_BITWISE_SREG] == NULL ||
60 tb[NFTA_BITWISE_DREG] == NULL ||
61 tb[NFTA_BITWISE_LEN] == NULL ||
62 tb[NFTA_BITWISE_MASK] == NULL ||
63 tb[NFTA_BITWISE_XOR] == NULL)
64 return -EINVAL;
65
66 priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
67 err = nft_validate_input_register(priv->sreg);
68 if (err < 0)
69 return err;
70
71 priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_DREG]));
72 err = nft_validate_output_register(priv->dreg);
73 if (err < 0)
74 return err;
75 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
76 if (err < 0)
77 return err;
78
79 priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
80
81 err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
82 if (err < 0)
83 return err;
84 if (d1.len != priv->len)
85 return -EINVAL;
86
87 err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]);
88 if (err < 0)
89 return err;
90 if (d2.len != priv->len)
91 return -EINVAL;
92
93 return 0;
94}
95
96static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
97{
98 const struct nft_bitwise *priv = nft_expr_priv(expr);
99
100 if (nla_put_be32(skb, NFTA_BITWISE_SREG, htonl(priv->sreg)))
101 goto nla_put_failure;
102 if (nla_put_be32(skb, NFTA_BITWISE_DREG, htonl(priv->dreg)))
103 goto nla_put_failure;
104 if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
105 goto nla_put_failure;
106
107 if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
108 NFT_DATA_VALUE, priv->len) < 0)
109 goto nla_put_failure;
110
111 if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
112 NFT_DATA_VALUE, priv->len) < 0)
113 goto nla_put_failure;
114
115 return 0;
116
117nla_put_failure:
118 return -1;
119}
120
121static struct nft_expr_type nft_bitwise_type;
122static const struct nft_expr_ops nft_bitwise_ops = {
123 .type = &nft_bitwise_type,
124 .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
125 .eval = nft_bitwise_eval,
126 .init = nft_bitwise_init,
127 .dump = nft_bitwise_dump,
128};
129
130static struct nft_expr_type nft_bitwise_type __read_mostly = {
131 .name = "bitwise",
132 .ops = &nft_bitwise_ops,
133 .policy = nft_bitwise_policy,
134 .maxattr = NFTA_BITWISE_MAX,
135 .owner = THIS_MODULE,
136};
137
138int __init nft_bitwise_module_init(void)
139{
140 return nft_register_expr(&nft_bitwise_type);
141}
142
143void nft_bitwise_module_exit(void)
144{
145 nft_unregister_expr(&nft_bitwise_type);
146}
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
new file mode 100644
index 000000000000..c39ed8d29df1
--- /dev/null
+++ b/net/netfilter/nft_byteorder.c
@@ -0,0 +1,173 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_byteorder {
21 enum nft_registers sreg:8;
22 enum nft_registers dreg:8;
23 enum nft_byteorder_ops op:8;
24 u8 len;
25 u8 size;
26};
27
28static void nft_byteorder_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 const struct nft_byteorder *priv = nft_expr_priv(expr);
33 struct nft_data *src = &data[priv->sreg], *dst = &data[priv->dreg];
34 union { u32 u32; u16 u16; } *s, *d;
35 unsigned int i;
36
37 s = (void *)src->data;
38 d = (void *)dst->data;
39
40 switch (priv->size) {
41 case 4:
42 switch (priv->op) {
43 case NFT_BYTEORDER_NTOH:
44 for (i = 0; i < priv->len / 4; i++)
45 d[i].u32 = ntohl((__force __be32)s[i].u32);
46 break;
47 case NFT_BYTEORDER_HTON:
48 for (i = 0; i < priv->len / 4; i++)
49 d[i].u32 = (__force __u32)htonl(s[i].u32);
50 break;
51 }
52 break;
53 case 2:
54 switch (priv->op) {
55 case NFT_BYTEORDER_NTOH:
56 for (i = 0; i < priv->len / 2; i++)
57 d[i].u16 = ntohs((__force __be16)s[i].u16);
58 break;
59 case NFT_BYTEORDER_HTON:
60 for (i = 0; i < priv->len / 2; i++)
61 d[i].u16 = (__force __u16)htons(s[i].u16);
62 break;
63 }
64 break;
65 }
66}
67
68static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
69 [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 },
70 [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 },
71 [NFTA_BYTEORDER_OP] = { .type = NLA_U32 },
72 [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 },
73 [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 },
74};
75
76static int nft_byteorder_init(const struct nft_ctx *ctx,
77 const struct nft_expr *expr,
78 const struct nlattr * const tb[])
79{
80 struct nft_byteorder *priv = nft_expr_priv(expr);
81 int err;
82
83 if (tb[NFTA_BYTEORDER_SREG] == NULL ||
84 tb[NFTA_BYTEORDER_DREG] == NULL ||
85 tb[NFTA_BYTEORDER_LEN] == NULL ||
86 tb[NFTA_BYTEORDER_SIZE] == NULL ||
87 tb[NFTA_BYTEORDER_OP] == NULL)
88 return -EINVAL;
89
90 priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
91 err = nft_validate_input_register(priv->sreg);
92 if (err < 0)
93 return err;
94
95 priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG]));
96 err = nft_validate_output_register(priv->dreg);
97 if (err < 0)
98 return err;
99 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
100 if (err < 0)
101 return err;
102
103 priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
104 switch (priv->op) {
105 case NFT_BYTEORDER_NTOH:
106 case NFT_BYTEORDER_HTON:
107 break;
108 default:
109 return -EINVAL;
110 }
111
112 priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
113 if (priv->len == 0 || priv->len > FIELD_SIZEOF(struct nft_data, data))
114 return -EINVAL;
115
116 priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
117 switch (priv->size) {
118 case 2:
119 case 4:
120 break;
121 default:
122 return -EINVAL;
123 }
124
125 return 0;
126}
127
128static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
129{
130 const struct nft_byteorder *priv = nft_expr_priv(expr);
131
132 if (nla_put_be32(skb, NFTA_BYTEORDER_SREG, htonl(priv->sreg)))
133 goto nla_put_failure;
134 if (nla_put_be32(skb, NFTA_BYTEORDER_DREG, htonl(priv->dreg)))
135 goto nla_put_failure;
136 if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
137 goto nla_put_failure;
138 if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
139 goto nla_put_failure;
140 if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
141 goto nla_put_failure;
142 return 0;
143
144nla_put_failure:
145 return -1;
146}
147
148static struct nft_expr_type nft_byteorder_type;
149static const struct nft_expr_ops nft_byteorder_ops = {
150 .type = &nft_byteorder_type,
151 .size = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
152 .eval = nft_byteorder_eval,
153 .init = nft_byteorder_init,
154 .dump = nft_byteorder_dump,
155};
156
157static struct nft_expr_type nft_byteorder_type __read_mostly = {
158 .name = "byteorder",
159 .ops = &nft_byteorder_ops,
160 .policy = nft_byteorder_policy,
161 .maxattr = NFTA_BYTEORDER_MAX,
162 .owner = THIS_MODULE,
163};
164
165int __init nft_byteorder_module_init(void)
166{
167 return nft_register_expr(&nft_byteorder_type);
168}
169
170void nft_byteorder_module_exit(void)
171{
172 nft_unregister_expr(&nft_byteorder_type);
173}
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
new file mode 100644
index 000000000000..954925db414d
--- /dev/null
+++ b/net/netfilter/nft_cmp.c
@@ -0,0 +1,223 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_cmp_expr {
21 struct nft_data data;
22 enum nft_registers sreg:8;
23 u8 len;
24 enum nft_cmp_ops op:8;
25};
26
27static void nft_cmp_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_cmp_expr *priv = nft_expr_priv(expr);
32 int d;
33
34 d = nft_data_cmp(&data[priv->sreg], &priv->data, priv->len);
35 switch (priv->op) {
36 case NFT_CMP_EQ:
37 if (d != 0)
38 goto mismatch;
39 break;
40 case NFT_CMP_NEQ:
41 if (d == 0)
42 goto mismatch;
43 break;
44 case NFT_CMP_LT:
45 if (d == 0)
46 goto mismatch;
47 case NFT_CMP_LTE:
48 if (d > 0)
49 goto mismatch;
50 break;
51 case NFT_CMP_GT:
52 if (d == 0)
53 goto mismatch;
54 case NFT_CMP_GTE:
55 if (d < 0)
56 goto mismatch;
57 break;
58 }
59 return;
60
61mismatch:
62 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
63}
64
65static const struct nla_policy nft_cmp_policy[NFTA_CMP_MAX + 1] = {
66 [NFTA_CMP_SREG] = { .type = NLA_U32 },
67 [NFTA_CMP_OP] = { .type = NLA_U32 },
68 [NFTA_CMP_DATA] = { .type = NLA_NESTED },
69};
70
71static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
72 const struct nlattr * const tb[])
73{
74 struct nft_cmp_expr *priv = nft_expr_priv(expr);
75 struct nft_data_desc desc;
76 int err;
77
78 priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
79 priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
80
81 err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
82 BUG_ON(err < 0);
83
84 priv->len = desc.len;
85 return 0;
86}
87
88static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
89{
90 const struct nft_cmp_expr *priv = nft_expr_priv(expr);
91
92 if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
93 goto nla_put_failure;
94 if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op)))
95 goto nla_put_failure;
96
97 if (nft_data_dump(skb, NFTA_CMP_DATA, &priv->data,
98 NFT_DATA_VALUE, priv->len) < 0)
99 goto nla_put_failure;
100 return 0;
101
102nla_put_failure:
103 return -1;
104}
105
106static struct nft_expr_type nft_cmp_type;
107static const struct nft_expr_ops nft_cmp_ops = {
108 .type = &nft_cmp_type,
109 .size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_expr)),
110 .eval = nft_cmp_eval,
111 .init = nft_cmp_init,
112 .dump = nft_cmp_dump,
113};
114
115static int nft_cmp_fast_init(const struct nft_ctx *ctx,
116 const struct nft_expr *expr,
117 const struct nlattr * const tb[])
118{
119 struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
120 struct nft_data_desc desc;
121 struct nft_data data;
122 u32 mask;
123 int err;
124
125 priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
126
127 err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
128 BUG_ON(err < 0);
129 desc.len *= BITS_PER_BYTE;
130
131 mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - desc.len);
132 priv->data = data.data[0] & mask;
133 priv->len = desc.len;
134 return 0;
135}
136
137static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
138{
139 const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
140 struct nft_data data;
141
142 if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
143 goto nla_put_failure;
144 if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
145 goto nla_put_failure;
146
147 data.data[0] = priv->data;
148 if (nft_data_dump(skb, NFTA_CMP_DATA, &data,
149 NFT_DATA_VALUE, priv->len / BITS_PER_BYTE) < 0)
150 goto nla_put_failure;
151 return 0;
152
153nla_put_failure:
154 return -1;
155}
156
157const struct nft_expr_ops nft_cmp_fast_ops = {
158 .type = &nft_cmp_type,
159 .size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_fast_expr)),
160 .eval = NULL, /* inlined */
161 .init = nft_cmp_fast_init,
162 .dump = nft_cmp_fast_dump,
163};
164
165static const struct nft_expr_ops *
166nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
167{
168 struct nft_data_desc desc;
169 struct nft_data data;
170 enum nft_registers sreg;
171 enum nft_cmp_ops op;
172 int err;
173
174 if (tb[NFTA_CMP_SREG] == NULL ||
175 tb[NFTA_CMP_OP] == NULL ||
176 tb[NFTA_CMP_DATA] == NULL)
177 return ERR_PTR(-EINVAL);
178
179 sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
180 err = nft_validate_input_register(sreg);
181 if (err < 0)
182 return ERR_PTR(err);
183
184 op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
185 switch (op) {
186 case NFT_CMP_EQ:
187 case NFT_CMP_NEQ:
188 case NFT_CMP_LT:
189 case NFT_CMP_LTE:
190 case NFT_CMP_GT:
191 case NFT_CMP_GTE:
192 break;
193 default:
194 return ERR_PTR(-EINVAL);
195 }
196
197 err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
198 if (err < 0)
199 return ERR_PTR(err);
200
201 if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ)
202 return &nft_cmp_fast_ops;
203 else
204 return &nft_cmp_ops;
205}
206
207static struct nft_expr_type nft_cmp_type __read_mostly = {
208 .name = "cmp",
209 .select_ops = nft_cmp_select_ops,
210 .policy = nft_cmp_policy,
211 .maxattr = NFTA_CMP_MAX,
212 .owner = THIS_MODULE,
213};
214
215int __init nft_cmp_module_init(void)
216{
217 return nft_register_expr(&nft_cmp_type);
218}
219
220void nft_cmp_module_exit(void)
221{
222 nft_unregister_expr(&nft_cmp_type);
223}
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
new file mode 100644
index 000000000000..4811f762e060
--- /dev/null
+++ b/net/netfilter/nft_compat.c
@@ -0,0 +1,768 @@
1/*
2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
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 * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nfnetlink.h>
17#include <linux/netfilter/nf_tables.h>
18#include <linux/netfilter/nf_tables_compat.h>
19#include <linux/netfilter/x_tables.h>
20#include <linux/netfilter_ipv4/ip_tables.h>
21#include <linux/netfilter_ipv6/ip6_tables.h>
22#include <asm/uaccess.h> /* for set_fs */
23#include <net/netfilter/nf_tables.h>
24
25union nft_entry {
26 struct ipt_entry e4;
27 struct ip6t_entry e6;
28};
29
30static inline void
31nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
32{
33 par->target = xt;
34 par->targinfo = xt_info;
35 par->hotdrop = false;
36}
37
38static void nft_target_eval(const struct nft_expr *expr,
39 struct nft_data data[NFT_REG_MAX + 1],
40 const struct nft_pktinfo *pkt)
41{
42 void *info = nft_expr_priv(expr);
43 struct xt_target *target = expr->ops->data;
44 struct sk_buff *skb = pkt->skb;
45 int ret;
46
47 nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
48
49 ret = target->target(skb, &pkt->xt);
50
51 if (pkt->xt.hotdrop)
52 ret = NF_DROP;
53
54 switch(ret) {
55 case XT_CONTINUE:
56 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
57 break;
58 default:
59 data[NFT_REG_VERDICT].verdict = ret;
60 break;
61 }
62 return;
63}
64
65static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
66 [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
67 [NFTA_TARGET_REV] = { .type = NLA_U32 },
68 [NFTA_TARGET_INFO] = { .type = NLA_BINARY },
69};
70
71static void
72nft_target_set_tgchk_param(struct xt_tgchk_param *par,
73 const struct nft_ctx *ctx,
74 struct xt_target *target, void *info,
75 union nft_entry *entry, u8 proto, bool inv)
76{
77 par->net = &init_net;
78 par->table = ctx->table->name;
79 switch (ctx->afi->family) {
80 case AF_INET:
81 entry->e4.ip.proto = proto;
82 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
83 break;
84 case AF_INET6:
85 entry->e6.ipv6.proto = proto;
86 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
87 break;
88 }
89 par->entryinfo = entry;
90 par->target = target;
91 par->targinfo = info;
92 if (ctx->chain->flags & NFT_BASE_CHAIN) {
93 const struct nft_base_chain *basechain =
94 nft_base_chain(ctx->chain);
95 const struct nf_hook_ops *ops = &basechain->ops;
96
97 par->hook_mask = 1 << ops->hooknum;
98 }
99 par->family = ctx->afi->family;
100}
101
102static void target_compat_from_user(struct xt_target *t, void *in, void *out)
103{
104#ifdef CONFIG_COMPAT
105 if (t->compat_from_user) {
106 int pad;
107
108 t->compat_from_user(out, in);
109 pad = XT_ALIGN(t->targetsize) - t->targetsize;
110 if (pad > 0)
111 memset(out + t->targetsize, 0, pad);
112 } else
113#endif
114 memcpy(out, in, XT_ALIGN(t->targetsize));
115}
116
117static inline int nft_compat_target_offset(struct xt_target *target)
118{
119#ifdef CONFIG_COMPAT
120 return xt_compat_target_offset(target);
121#else
122 return 0;
123#endif
124}
125
126static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
127 [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 },
128 [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 },
129};
130
131static u8 nft_parse_compat(const struct nlattr *attr, bool *inv)
132{
133 struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
134 u32 flags;
135 int err;
136
137 err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
138 nft_rule_compat_policy);
139 if (err < 0)
140 return err;
141
142 if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
143 return -EINVAL;
144
145 flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
146 if (flags & ~NFT_RULE_COMPAT_F_MASK)
147 return -EINVAL;
148 if (flags & NFT_RULE_COMPAT_F_INV)
149 *inv = true;
150
151 return ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
152}
153
154static int
155nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
156 const struct nlattr * const tb[])
157{
158 void *info = nft_expr_priv(expr);
159 struct xt_target *target = expr->ops->data;
160 struct xt_tgchk_param par;
161 size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
162 u8 proto = 0;
163 bool inv = false;
164 union nft_entry e = {};
165 int ret;
166
167 target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
168
169 if (ctx->nla[NFTA_RULE_COMPAT])
170 proto = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &inv);
171
172 nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
173
174 ret = xt_check_target(&par, size, proto, inv);
175 if (ret < 0)
176 goto err;
177
178 /* The standard target cannot be used */
179 if (target->target == NULL) {
180 ret = -EINVAL;
181 goto err;
182 }
183
184 return 0;
185err:
186 module_put(target->me);
187 return ret;
188}
189
190static void
191nft_target_destroy(const struct nft_expr *expr)
192{
193 struct xt_target *target = expr->ops->data;
194
195 module_put(target->me);
196}
197
198static int
199target_dump_info(struct sk_buff *skb, const struct xt_target *t, const void *in)
200{
201 int ret;
202
203#ifdef CONFIG_COMPAT
204 if (t->compat_to_user) {
205 mm_segment_t old_fs;
206 void *out;
207
208 out = kmalloc(XT_ALIGN(t->targetsize), GFP_ATOMIC);
209 if (out == NULL)
210 return -ENOMEM;
211
212 /* We want to reuse existing compat_to_user */
213 old_fs = get_fs();
214 set_fs(KERNEL_DS);
215 t->compat_to_user(out, in);
216 set_fs(old_fs);
217 ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), out);
218 kfree(out);
219 } else
220#endif
221 ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), in);
222
223 return ret;
224}
225
226static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
227{
228 const struct xt_target *target = expr->ops->data;
229 void *info = nft_expr_priv(expr);
230
231 if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
232 nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
233 target_dump_info(skb, target, info))
234 goto nla_put_failure;
235
236 return 0;
237
238nla_put_failure:
239 return -1;
240}
241
242static int nft_target_validate(const struct nft_ctx *ctx,
243 const struct nft_expr *expr,
244 const struct nft_data **data)
245{
246 struct xt_target *target = expr->ops->data;
247 unsigned int hook_mask = 0;
248
249 if (ctx->chain->flags & NFT_BASE_CHAIN) {
250 const struct nft_base_chain *basechain =
251 nft_base_chain(ctx->chain);
252 const struct nf_hook_ops *ops = &basechain->ops;
253
254 hook_mask = 1 << ops->hooknum;
255 if (hook_mask & target->hooks)
256 return 0;
257
258 /* This target is being called from an invalid chain */
259 return -EINVAL;
260 }
261 return 0;
262}
263
264static void nft_match_eval(const struct nft_expr *expr,
265 struct nft_data data[NFT_REG_MAX + 1],
266 const struct nft_pktinfo *pkt)
267{
268 void *info = nft_expr_priv(expr);
269 struct xt_match *match = expr->ops->data;
270 struct sk_buff *skb = pkt->skb;
271 bool ret;
272
273 nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
274
275 ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
276
277 if (pkt->xt.hotdrop) {
278 data[NFT_REG_VERDICT].verdict = NF_DROP;
279 return;
280 }
281
282 switch(ret) {
283 case true:
284 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
285 break;
286 case false:
287 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
288 break;
289 }
290}
291
292static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
293 [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
294 [NFTA_MATCH_REV] = { .type = NLA_U32 },
295 [NFTA_MATCH_INFO] = { .type = NLA_BINARY },
296};
297
298/* struct xt_mtchk_param and xt_tgchk_param look very similar */
299static void
300nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
301 struct xt_match *match, void *info,
302 union nft_entry *entry, u8 proto, bool inv)
303{
304 par->net = &init_net;
305 par->table = ctx->table->name;
306 switch (ctx->afi->family) {
307 case AF_INET:
308 entry->e4.ip.proto = proto;
309 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
310 break;
311 case AF_INET6:
312 entry->e6.ipv6.proto = proto;
313 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
314 break;
315 }
316 par->entryinfo = entry;
317 par->match = match;
318 par->matchinfo = info;
319 if (ctx->chain->flags & NFT_BASE_CHAIN) {
320 const struct nft_base_chain *basechain =
321 nft_base_chain(ctx->chain);
322 const struct nf_hook_ops *ops = &basechain->ops;
323
324 par->hook_mask = 1 << ops->hooknum;
325 }
326 par->family = ctx->afi->family;
327}
328
329static void match_compat_from_user(struct xt_match *m, void *in, void *out)
330{
331#ifdef CONFIG_COMPAT
332 if (m->compat_from_user) {
333 int pad;
334
335 m->compat_from_user(out, in);
336 pad = XT_ALIGN(m->matchsize) - m->matchsize;
337 if (pad > 0)
338 memset(out + m->matchsize, 0, pad);
339 } else
340#endif
341 memcpy(out, in, XT_ALIGN(m->matchsize));
342}
343
344static int
345nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
346 const struct nlattr * const tb[])
347{
348 void *info = nft_expr_priv(expr);
349 struct xt_match *match = expr->ops->data;
350 struct xt_mtchk_param par;
351 size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
352 u8 proto = 0;
353 bool inv = false;
354 union nft_entry e = {};
355 int ret;
356
357 match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
358
359 if (ctx->nla[NFTA_RULE_COMPAT])
360 proto = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &inv);
361
362 nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
363
364 ret = xt_check_match(&par, size, proto, inv);
365 if (ret < 0)
366 goto err;
367
368 return 0;
369err:
370 module_put(match->me);
371 return ret;
372}
373
374static void
375nft_match_destroy(const struct nft_expr *expr)
376{
377 struct xt_match *match = expr->ops->data;
378
379 module_put(match->me);
380}
381
382static int
383match_dump_info(struct sk_buff *skb, const struct xt_match *m, const void *in)
384{
385 int ret;
386
387#ifdef CONFIG_COMPAT
388 if (m->compat_to_user) {
389 mm_segment_t old_fs;
390 void *out;
391
392 out = kmalloc(XT_ALIGN(m->matchsize), GFP_ATOMIC);
393 if (out == NULL)
394 return -ENOMEM;
395
396 /* We want to reuse existing compat_to_user */
397 old_fs = get_fs();
398 set_fs(KERNEL_DS);
399 m->compat_to_user(out, in);
400 set_fs(old_fs);
401 ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), out);
402 kfree(out);
403 } else
404#endif
405 ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), in);
406
407 return ret;
408}
409
410static inline int nft_compat_match_offset(struct xt_match *match)
411{
412#ifdef CONFIG_COMPAT
413 return xt_compat_match_offset(match);
414#else
415 return 0;
416#endif
417}
418
419static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
420{
421 void *info = nft_expr_priv(expr);
422 struct xt_match *match = expr->ops->data;
423
424 if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
425 nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
426 match_dump_info(skb, match, info))
427 goto nla_put_failure;
428
429 return 0;
430
431nla_put_failure:
432 return -1;
433}
434
435static int nft_match_validate(const struct nft_ctx *ctx,
436 const struct nft_expr *expr,
437 const struct nft_data **data)
438{
439 struct xt_match *match = expr->ops->data;
440 unsigned int hook_mask = 0;
441
442 if (ctx->chain->flags & NFT_BASE_CHAIN) {
443 const struct nft_base_chain *basechain =
444 nft_base_chain(ctx->chain);
445 const struct nf_hook_ops *ops = &basechain->ops;
446
447 hook_mask = 1 << ops->hooknum;
448 if (hook_mask & match->hooks)
449 return 0;
450
451 /* This match is being called from an invalid chain */
452 return -EINVAL;
453 }
454 return 0;
455}
456
457static int
458nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
459 int event, u16 family, const char *name,
460 int rev, int target)
461{
462 struct nlmsghdr *nlh;
463 struct nfgenmsg *nfmsg;
464 unsigned int flags = portid ? NLM_F_MULTI : 0;
465
466 event |= NFNL_SUBSYS_NFT_COMPAT << 8;
467 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
468 if (nlh == NULL)
469 goto nlmsg_failure;
470
471 nfmsg = nlmsg_data(nlh);
472 nfmsg->nfgen_family = family;
473 nfmsg->version = NFNETLINK_V0;
474 nfmsg->res_id = 0;
475
476 if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
477 nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
478 nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
479 goto nla_put_failure;
480
481 nlmsg_end(skb, nlh);
482 return skb->len;
483
484nlmsg_failure:
485nla_put_failure:
486 nlmsg_cancel(skb, nlh);
487 return -1;
488}
489
490static int
491nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
492 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
493{
494 int ret = 0, target;
495 struct nfgenmsg *nfmsg;
496 const char *fmt;
497 const char *name;
498 u32 rev;
499 struct sk_buff *skb2;
500
501 if (tb[NFTA_COMPAT_NAME] == NULL ||
502 tb[NFTA_COMPAT_REV] == NULL ||
503 tb[NFTA_COMPAT_TYPE] == NULL)
504 return -EINVAL;
505
506 name = nla_data(tb[NFTA_COMPAT_NAME]);
507 rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
508 target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
509
510 nfmsg = nlmsg_data(nlh);
511
512 switch(nfmsg->nfgen_family) {
513 case AF_INET:
514 fmt = "ipt_%s";
515 break;
516 case AF_INET6:
517 fmt = "ip6t_%s";
518 break;
519 default:
520 pr_err("nft_compat: unsupported protocol %d\n",
521 nfmsg->nfgen_family);
522 return -EINVAL;
523 }
524
525 try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
526 rev, target, &ret),
527 fmt, name);
528
529 if (ret < 0)
530 return ret;
531
532 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
533 if (skb2 == NULL)
534 return -ENOMEM;
535
536 /* include the best revision for this extension in the message */
537 if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
538 nlh->nlmsg_seq,
539 NFNL_MSG_TYPE(nlh->nlmsg_type),
540 NFNL_MSG_COMPAT_GET,
541 nfmsg->nfgen_family,
542 name, ret, target) <= 0) {
543 kfree_skb(skb2);
544 return -ENOSPC;
545 }
546
547 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
548 MSG_DONTWAIT);
549 if (ret > 0)
550 ret = 0;
551
552 return ret == -EAGAIN ? -ENOBUFS : ret;
553}
554
555static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
556 [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING,
557 .len = NFT_COMPAT_NAME_MAX-1 },
558 [NFTA_COMPAT_REV] = { .type = NLA_U32 },
559 [NFTA_COMPAT_TYPE] = { .type = NLA_U32 },
560};
561
562static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
563 [NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get,
564 .attr_count = NFTA_COMPAT_MAX,
565 .policy = nfnl_compat_policy_get },
566};
567
568static const struct nfnetlink_subsystem nfnl_compat_subsys = {
569 .name = "nft-compat",
570 .subsys_id = NFNL_SUBSYS_NFT_COMPAT,
571 .cb_count = NFNL_MSG_COMPAT_MAX,
572 .cb = nfnl_nft_compat_cb,
573};
574
575static LIST_HEAD(nft_match_list);
576
577struct nft_xt {
578 struct list_head head;
579 struct nft_expr_ops ops;
580};
581
582static struct nft_expr_type nft_match_type;
583
584static const struct nft_expr_ops *
585nft_match_select_ops(const struct nft_ctx *ctx,
586 const struct nlattr * const tb[])
587{
588 struct nft_xt *nft_match;
589 struct xt_match *match;
590 char *mt_name;
591 __u32 rev, family;
592
593 if (tb[NFTA_MATCH_NAME] == NULL ||
594 tb[NFTA_MATCH_REV] == NULL ||
595 tb[NFTA_MATCH_INFO] == NULL)
596 return ERR_PTR(-EINVAL);
597
598 mt_name = nla_data(tb[NFTA_MATCH_NAME]);
599 rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
600 family = ctx->afi->family;
601
602 /* Re-use the existing match if it's already loaded. */
603 list_for_each_entry(nft_match, &nft_match_list, head) {
604 struct xt_match *match = nft_match->ops.data;
605
606 if (strcmp(match->name, mt_name) == 0 &&
607 match->revision == rev && match->family == family)
608 return &nft_match->ops;
609 }
610
611 match = xt_request_find_match(family, mt_name, rev);
612 if (IS_ERR(match))
613 return ERR_PTR(-ENOENT);
614
615 /* This is the first time we use this match, allocate operations */
616 nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
617 if (nft_match == NULL)
618 return ERR_PTR(-ENOMEM);
619
620 nft_match->ops.type = &nft_match_type;
621 nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize) +
622 nft_compat_match_offset(match));
623 nft_match->ops.eval = nft_match_eval;
624 nft_match->ops.init = nft_match_init;
625 nft_match->ops.destroy = nft_match_destroy;
626 nft_match->ops.dump = nft_match_dump;
627 nft_match->ops.validate = nft_match_validate;
628 nft_match->ops.data = match;
629
630 list_add(&nft_match->head, &nft_match_list);
631
632 return &nft_match->ops;
633}
634
635static void nft_match_release(void)
636{
637 struct nft_xt *nft_match;
638
639 list_for_each_entry(nft_match, &nft_match_list, head)
640 kfree(nft_match);
641}
642
643static struct nft_expr_type nft_match_type __read_mostly = {
644 .name = "match",
645 .select_ops = nft_match_select_ops,
646 .policy = nft_match_policy,
647 .maxattr = NFTA_MATCH_MAX,
648 .owner = THIS_MODULE,
649};
650
651static LIST_HEAD(nft_target_list);
652
653static struct nft_expr_type nft_target_type;
654
655static const struct nft_expr_ops *
656nft_target_select_ops(const struct nft_ctx *ctx,
657 const struct nlattr * const tb[])
658{
659 struct nft_xt *nft_target;
660 struct xt_target *target;
661 char *tg_name;
662 __u32 rev, family;
663
664 if (tb[NFTA_TARGET_NAME] == NULL ||
665 tb[NFTA_TARGET_REV] == NULL ||
666 tb[NFTA_TARGET_INFO] == NULL)
667 return ERR_PTR(-EINVAL);
668
669 tg_name = nla_data(tb[NFTA_TARGET_NAME]);
670 rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
671 family = ctx->afi->family;
672
673 /* Re-use the existing target if it's already loaded. */
674 list_for_each_entry(nft_target, &nft_match_list, head) {
675 struct xt_target *target = nft_target->ops.data;
676
677 if (strcmp(target->name, tg_name) == 0 &&
678 target->revision == rev && target->family == family)
679 return &nft_target->ops;
680 }
681
682 target = xt_request_find_target(family, tg_name, rev);
683 if (IS_ERR(target))
684 return ERR_PTR(-ENOENT);
685
686 /* This is the first time we use this target, allocate operations */
687 nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
688 if (nft_target == NULL)
689 return ERR_PTR(-ENOMEM);
690
691 nft_target->ops.type = &nft_target_type;
692 nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize) +
693 nft_compat_target_offset(target));
694 nft_target->ops.eval = nft_target_eval;
695 nft_target->ops.init = nft_target_init;
696 nft_target->ops.destroy = nft_target_destroy;
697 nft_target->ops.dump = nft_target_dump;
698 nft_target->ops.validate = nft_target_validate;
699 nft_target->ops.data = target;
700
701 list_add(&nft_target->head, &nft_target_list);
702
703 return &nft_target->ops;
704}
705
706static void nft_target_release(void)
707{
708 struct nft_xt *nft_target;
709
710 list_for_each_entry(nft_target, &nft_target_list, head)
711 kfree(nft_target);
712}
713
714static struct nft_expr_type nft_target_type __read_mostly = {
715 .name = "target",
716 .select_ops = nft_target_select_ops,
717 .policy = nft_target_policy,
718 .maxattr = NFTA_TARGET_MAX,
719 .owner = THIS_MODULE,
720};
721
722static int __init nft_compat_module_init(void)
723{
724 int ret;
725
726 ret = nft_register_expr(&nft_match_type);
727 if (ret < 0)
728 return ret;
729
730 ret = nft_register_expr(&nft_target_type);
731 if (ret < 0)
732 goto err_match;
733
734 ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
735 if (ret < 0) {
736 pr_err("nft_compat: cannot register with nfnetlink.\n");
737 goto err_target;
738 }
739
740 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
741
742 return ret;
743
744err_target:
745 nft_unregister_expr(&nft_target_type);
746err_match:
747 nft_unregister_expr(&nft_match_type);
748 return ret;
749}
750
751static void __exit nft_compat_module_exit(void)
752{
753 nfnetlink_subsys_unregister(&nfnl_compat_subsys);
754 nft_unregister_expr(&nft_target_type);
755 nft_unregister_expr(&nft_match_type);
756 nft_match_release();
757 nft_target_release();
758}
759
760MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
761
762module_init(nft_compat_module_init);
763module_exit(nft_compat_module_exit);
764
765MODULE_LICENSE("GPL");
766MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
767MODULE_ALIAS_NFT_EXPR("match");
768MODULE_ALIAS_NFT_EXPR("target");
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
new file mode 100644
index 000000000000..c89ee486ce54
--- /dev/null
+++ b/net/netfilter/nft_counter.c
@@ -0,0 +1,113 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/seqlock.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_counter {
21 seqlock_t lock;
22 u64 bytes;
23 u64 packets;
24};
25
26static void nft_counter_eval(const struct nft_expr *expr,
27 struct nft_data data[NFT_REG_MAX + 1],
28 const struct nft_pktinfo *pkt)
29{
30 struct nft_counter *priv = nft_expr_priv(expr);
31
32 write_seqlock_bh(&priv->lock);
33 priv->bytes += pkt->skb->len;
34 priv->packets++;
35 write_sequnlock_bh(&priv->lock);
36}
37
38static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
39{
40 struct nft_counter *priv = nft_expr_priv(expr);
41 unsigned int seq;
42 u64 bytes;
43 u64 packets;
44
45 do {
46 seq = read_seqbegin(&priv->lock);
47 bytes = priv->bytes;
48 packets = priv->packets;
49 } while (read_seqretry(&priv->lock, seq));
50
51 if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(bytes)))
52 goto nla_put_failure;
53 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(packets)))
54 goto nla_put_failure;
55 return 0;
56
57nla_put_failure:
58 return -1;
59}
60
61static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
62 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
63 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
64};
65
66static int nft_counter_init(const struct nft_ctx *ctx,
67 const struct nft_expr *expr,
68 const struct nlattr * const tb[])
69{
70 struct nft_counter *priv = nft_expr_priv(expr);
71
72 if (tb[NFTA_COUNTER_PACKETS])
73 priv->packets = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
74 if (tb[NFTA_COUNTER_BYTES])
75 priv->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
76
77 seqlock_init(&priv->lock);
78 return 0;
79}
80
81static struct nft_expr_type nft_counter_type;
82static const struct nft_expr_ops nft_counter_ops = {
83 .type = &nft_counter_type,
84 .size = NFT_EXPR_SIZE(sizeof(struct nft_counter)),
85 .eval = nft_counter_eval,
86 .init = nft_counter_init,
87 .dump = nft_counter_dump,
88};
89
90static struct nft_expr_type nft_counter_type __read_mostly = {
91 .name = "counter",
92 .ops = &nft_counter_ops,
93 .policy = nft_counter_policy,
94 .maxattr = NFTA_COUNTER_MAX,
95 .owner = THIS_MODULE,
96};
97
98static int __init nft_counter_module_init(void)
99{
100 return nft_register_expr(&nft_counter_type);
101}
102
103static void __exit nft_counter_module_exit(void)
104{
105 nft_unregister_expr(&nft_counter_type);
106}
107
108module_init(nft_counter_module_init);
109module_exit(nft_counter_module_exit);
110
111MODULE_LICENSE("GPL");
112MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
113MODULE_ALIAS_NFT_EXPR("counter");
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
new file mode 100644
index 000000000000..955f4e6e7089
--- /dev/null
+++ b/net/netfilter/nft_ct.c
@@ -0,0 +1,258 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_tuple.h>
20#include <net/netfilter/nf_conntrack_helper.h>
21
22struct nft_ct {
23 enum nft_ct_keys key:8;
24 enum ip_conntrack_dir dir:8;
25 enum nft_registers dreg:8;
26 uint8_t family;
27};
28
29static void nft_ct_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 const struct nft_ct *priv = nft_expr_priv(expr);
34 struct nft_data *dest = &data[priv->dreg];
35 enum ip_conntrack_info ctinfo;
36 const struct nf_conn *ct;
37 const struct nf_conn_help *help;
38 const struct nf_conntrack_tuple *tuple;
39 const struct nf_conntrack_helper *helper;
40 long diff;
41 unsigned int state;
42
43 ct = nf_ct_get(pkt->skb, &ctinfo);
44
45 switch (priv->key) {
46 case NFT_CT_STATE:
47 if (ct == NULL)
48 state = NF_CT_STATE_INVALID_BIT;
49 else if (nf_ct_is_untracked(ct))
50 state = NF_CT_STATE_UNTRACKED_BIT;
51 else
52 state = NF_CT_STATE_BIT(ctinfo);
53 dest->data[0] = state;
54 return;
55 }
56
57 if (ct == NULL)
58 goto err;
59
60 switch (priv->key) {
61 case NFT_CT_DIRECTION:
62 dest->data[0] = CTINFO2DIR(ctinfo);
63 return;
64 case NFT_CT_STATUS:
65 dest->data[0] = ct->status;
66 return;
67#ifdef CONFIG_NF_CONNTRACK_MARK
68 case NFT_CT_MARK:
69 dest->data[0] = ct->mark;
70 return;
71#endif
72#ifdef CONFIG_NF_CONNTRACK_SECMARK
73 case NFT_CT_SECMARK:
74 dest->data[0] = ct->secmark;
75 return;
76#endif
77 case NFT_CT_EXPIRATION:
78 diff = (long)jiffies - (long)ct->timeout.expires;
79 if (diff < 0)
80 diff = 0;
81 dest->data[0] = jiffies_to_msecs(diff);
82 return;
83 case NFT_CT_HELPER:
84 if (ct->master == NULL)
85 goto err;
86 help = nfct_help(ct->master);
87 if (help == NULL)
88 goto err;
89 helper = rcu_dereference(help->helper);
90 if (helper == NULL)
91 goto err;
92 if (strlen(helper->name) >= sizeof(dest->data))
93 goto err;
94 strncpy((char *)dest->data, helper->name, sizeof(dest->data));
95 return;
96 }
97
98 tuple = &ct->tuplehash[priv->dir].tuple;
99 switch (priv->key) {
100 case NFT_CT_L3PROTOCOL:
101 dest->data[0] = nf_ct_l3num(ct);
102 return;
103 case NFT_CT_SRC:
104 memcpy(dest->data, tuple->src.u3.all,
105 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
106 return;
107 case NFT_CT_DST:
108 memcpy(dest->data, tuple->dst.u3.all,
109 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
110 return;
111 case NFT_CT_PROTOCOL:
112 dest->data[0] = nf_ct_protonum(ct);
113 return;
114 case NFT_CT_PROTO_SRC:
115 dest->data[0] = (__force __u16)tuple->src.u.all;
116 return;
117 case NFT_CT_PROTO_DST:
118 dest->data[0] = (__force __u16)tuple->dst.u.all;
119 return;
120 }
121 return;
122err:
123 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
124}
125
126static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
127 [NFTA_CT_DREG] = { .type = NLA_U32 },
128 [NFTA_CT_KEY] = { .type = NLA_U32 },
129 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
130};
131
132static int nft_ct_init(const struct nft_ctx *ctx,
133 const struct nft_expr *expr,
134 const struct nlattr * const tb[])
135{
136 struct nft_ct *priv = nft_expr_priv(expr);
137 int err;
138
139 if (tb[NFTA_CT_DREG] == NULL ||
140 tb[NFTA_CT_KEY] == NULL)
141 return -EINVAL;
142
143 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
144 if (tb[NFTA_CT_DIRECTION] != NULL) {
145 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
146 switch (priv->dir) {
147 case IP_CT_DIR_ORIGINAL:
148 case IP_CT_DIR_REPLY:
149 break;
150 default:
151 return -EINVAL;
152 }
153 }
154
155 switch (priv->key) {
156 case NFT_CT_STATE:
157 case NFT_CT_DIRECTION:
158 case NFT_CT_STATUS:
159#ifdef CONFIG_NF_CONNTRACK_MARK
160 case NFT_CT_MARK:
161#endif
162#ifdef CONFIG_NF_CONNTRACK_SECMARK
163 case NFT_CT_SECMARK:
164#endif
165 case NFT_CT_EXPIRATION:
166 case NFT_CT_HELPER:
167 if (tb[NFTA_CT_DIRECTION] != NULL)
168 return -EINVAL;
169 break;
170 case NFT_CT_PROTOCOL:
171 case NFT_CT_SRC:
172 case NFT_CT_DST:
173 case NFT_CT_PROTO_SRC:
174 case NFT_CT_PROTO_DST:
175 if (tb[NFTA_CT_DIRECTION] == NULL)
176 return -EINVAL;
177 break;
178 default:
179 return -EOPNOTSUPP;
180 }
181
182 err = nf_ct_l3proto_try_module_get(ctx->afi->family);
183 if (err < 0)
184 return err;
185 priv->family = ctx->afi->family;
186
187 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
188 err = nft_validate_output_register(priv->dreg);
189 if (err < 0)
190 goto err1;
191
192 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
193 if (err < 0)
194 goto err1;
195 return 0;
196
197err1:
198 nf_ct_l3proto_module_put(ctx->afi->family);
199 return err;
200}
201
202static void nft_ct_destroy(const struct nft_expr *expr)
203{
204 struct nft_ct *priv = nft_expr_priv(expr);
205
206 nf_ct_l3proto_module_put(priv->family);
207}
208
209static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr)
210{
211 const struct nft_ct *priv = nft_expr_priv(expr);
212
213 if (nla_put_be32(skb, NFTA_CT_DREG, htonl(priv->dreg)))
214 goto nla_put_failure;
215 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
216 goto nla_put_failure;
217 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
218 goto nla_put_failure;
219 return 0;
220
221nla_put_failure:
222 return -1;
223}
224
225static struct nft_expr_type nft_ct_type;
226static const struct nft_expr_ops nft_ct_ops = {
227 .type = &nft_ct_type,
228 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
229 .eval = nft_ct_eval,
230 .init = nft_ct_init,
231 .destroy = nft_ct_destroy,
232 .dump = nft_ct_dump,
233};
234
235static struct nft_expr_type nft_ct_type __read_mostly = {
236 .name = "ct",
237 .ops = &nft_ct_ops,
238 .policy = nft_ct_policy,
239 .maxattr = NFTA_CT_MAX,
240 .owner = THIS_MODULE,
241};
242
243static int __init nft_ct_module_init(void)
244{
245 return nft_register_expr(&nft_ct_type);
246}
247
248static void __exit nft_ct_module_exit(void)
249{
250 nft_unregister_expr(&nft_ct_type);
251}
252
253module_init(nft_ct_module_init);
254module_exit(nft_ct_module_exit);
255
256MODULE_LICENSE("GPL");
257MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
258MODULE_ALIAS_NFT_EXPR("ct");
diff --git a/net/netfilter/nft_expr_template.c b/net/netfilter/nft_expr_template.c
new file mode 100644
index 000000000000..b6eed4d5a096
--- /dev/null
+++ b/net/netfilter/nft_expr_template.c
@@ -0,0 +1,94 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/netlink.h>
14#include <linux/netfilter.h>
15#include <linux/netfilter/nf_tables.h>
16#include <net/netfilter/nf_tables.h>
17
18struct nft_template {
19
20};
21
22static void nft_template_eval(const struct nft_expr *expr,
23 struct nft_data data[NFT_REG_MAX + 1],
24 const struct nft_pktinfo *pkt)
25{
26 struct nft_template *priv = nft_expr_priv(expr);
27
28}
29
30static const struct nla_policy nft_template_policy[NFTA_TEMPLATE_MAX + 1] = {
31 [NFTA_TEMPLATE_ATTR] = { .type = NLA_U32 },
32};
33
34static int nft_template_init(const struct nft_ctx *ctx,
35 const struct nft_expr *expr,
36 const struct nlattr * const tb[])
37{
38 struct nft_template *priv = nft_expr_priv(expr);
39
40 return 0;
41}
42
43static void nft_template_destroy(const struct nft_ctx *ctx,
44 const struct nft_expr *expr)
45{
46 struct nft_template *priv = nft_expr_priv(expr);
47
48}
49
50static int nft_template_dump(struct sk_buff *skb, const struct nft_expr *expr)
51{
52 const struct nft_template *priv = nft_expr_priv(expr);
53
54 NLA_PUT_BE32(skb, NFTA_TEMPLATE_ATTR, priv->field);
55 return 0;
56
57nla_put_failure:
58 return -1;
59}
60
61static struct nft_expr_type nft_template_type;
62static const struct nft_expr_ops nft_template_ops = {
63 .type = &nft_template_type,
64 .size = NFT_EXPR_SIZE(sizeof(struct nft_template)),
65 .eval = nft_template_eval,
66 .init = nft_template_init,
67 .destroy = nft_template_destroy,
68 .dump = nft_template_dump,
69};
70
71static struct nft_expr_type nft_template_type __read_mostly = {
72 .name = "template",
73 .ops = &nft_template_ops,
74 .policy = nft_template_policy,
75 .maxattr = NFTA_TEMPLATE_MAX,
76 .owner = THIS_MODULE,
77};
78
79static int __init nft_template_module_init(void)
80{
81 return nft_register_expr(&nft_template_type);
82}
83
84static void __exit nft_template_module_exit(void)
85{
86 nft_unregister_expr(&nft_template_type);
87}
88
89module_init(nft_template_module_init);
90module_exit(nft_template_module_exit);
91
92MODULE_LICENSE("GPL");
93MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
94MODULE_ALIAS_NFT_EXPR("template");
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
new file mode 100644
index 000000000000..8e0bb75e7c51
--- /dev/null
+++ b/net/netfilter/nft_exthdr.c
@@ -0,0 +1,133 @@
1/*
2 * Copyright (c) 2008 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18// FIXME:
19#include <net/ipv6.h>
20
21struct nft_exthdr {
22 u8 type;
23 u8 offset;
24 u8 len;
25 enum nft_registers dreg:8;
26};
27
28static void nft_exthdr_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 struct nft_exthdr *priv = nft_expr_priv(expr);
33 struct nft_data *dest = &data[priv->dreg];
34 unsigned int offset;
35 int err;
36
37 err = ipv6_find_hdr(pkt->skb, &offset, priv->type, NULL, NULL);
38 if (err < 0)
39 goto err;
40 offset += priv->offset;
41
42 if (skb_copy_bits(pkt->skb, offset, dest->data, priv->len) < 0)
43 goto err;
44 return;
45err:
46 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
47}
48
49static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
50 [NFTA_EXTHDR_DREG] = { .type = NLA_U32 },
51 [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 },
52 [NFTA_EXTHDR_OFFSET] = { .type = NLA_U32 },
53 [NFTA_EXTHDR_LEN] = { .type = NLA_U32 },
54};
55
56static int nft_exthdr_init(const struct nft_ctx *ctx,
57 const struct nft_expr *expr,
58 const struct nlattr * const tb[])
59{
60 struct nft_exthdr *priv = nft_expr_priv(expr);
61 int err;
62
63 if (tb[NFTA_EXTHDR_DREG] == NULL ||
64 tb[NFTA_EXTHDR_TYPE] == NULL ||
65 tb[NFTA_EXTHDR_OFFSET] == NULL ||
66 tb[NFTA_EXTHDR_LEN] == NULL)
67 return -EINVAL;
68
69 priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
70 priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
71 priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
72 if (priv->len == 0 ||
73 priv->len > FIELD_SIZEOF(struct nft_data, data))
74 return -EINVAL;
75
76 priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG]));
77 err = nft_validate_output_register(priv->dreg);
78 if (err < 0)
79 return err;
80 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
81}
82
83static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)
84{
85 const struct nft_exthdr *priv = nft_expr_priv(expr);
86
87 if (nla_put_be32(skb, NFTA_EXTHDR_DREG, htonl(priv->dreg)))
88 goto nla_put_failure;
89 if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
90 goto nla_put_failure;
91 if (nla_put_be32(skb, NFTA_EXTHDR_OFFSET, htonl(priv->offset)))
92 goto nla_put_failure;
93 if (nla_put_be32(skb, NFTA_EXTHDR_LEN, htonl(priv->len)))
94 goto nla_put_failure;
95 return 0;
96
97nla_put_failure:
98 return -1;
99}
100
101static struct nft_expr_type nft_exthdr_type;
102static const struct nft_expr_ops nft_exthdr_ops = {
103 .type = &nft_exthdr_type,
104 .size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
105 .eval = nft_exthdr_eval,
106 .init = nft_exthdr_init,
107 .dump = nft_exthdr_dump,
108};
109
110static struct nft_expr_type nft_exthdr_type __read_mostly = {
111 .name = "exthdr",
112 .ops = &nft_exthdr_ops,
113 .policy = nft_exthdr_policy,
114 .maxattr = NFTA_EXTHDR_MAX,
115 .owner = THIS_MODULE,
116};
117
118static int __init nft_exthdr_module_init(void)
119{
120 return nft_register_expr(&nft_exthdr_type);
121}
122
123static void __exit nft_exthdr_module_exit(void)
124{
125 nft_unregister_expr(&nft_exthdr_type);
126}
127
128module_init(nft_exthdr_module_init);
129module_exit(nft_exthdr_module_exit);
130
131MODULE_LICENSE("GPL");
132MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
133MODULE_ALIAS_NFT_EXPR("exthdr");
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
new file mode 100644
index 000000000000..3d3f8fce10a5
--- /dev/null
+++ b/net/netfilter/nft_hash.c
@@ -0,0 +1,231 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/list.h>
15#include <linux/jhash.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_hash {
22 struct hlist_head *hash;
23 unsigned int hsize;
24};
25
26struct nft_hash_elem {
27 struct hlist_node hnode;
28 struct nft_data key;
29 struct nft_data data[];
30};
31
32static u32 nft_hash_rnd __read_mostly;
33static bool nft_hash_rnd_initted __read_mostly;
34
35static unsigned int nft_hash_data(const struct nft_data *data,
36 unsigned int hsize, unsigned int len)
37{
38 unsigned int h;
39
40 h = jhash(data->data, len, nft_hash_rnd);
41 return ((u64)h * hsize) >> 32;
42}
43
44static bool nft_hash_lookup(const struct nft_set *set,
45 const struct nft_data *key,
46 struct nft_data *data)
47{
48 const struct nft_hash *priv = nft_set_priv(set);
49 const struct nft_hash_elem *he;
50 unsigned int h;
51
52 h = nft_hash_data(key, priv->hsize, set->klen);
53 hlist_for_each_entry(he, &priv->hash[h], hnode) {
54 if (nft_data_cmp(&he->key, key, set->klen))
55 continue;
56 if (set->flags & NFT_SET_MAP)
57 nft_data_copy(data, he->data);
58 return true;
59 }
60 return false;
61}
62
63static void nft_hash_elem_destroy(const struct nft_set *set,
64 struct nft_hash_elem *he)
65{
66 nft_data_uninit(&he->key, NFT_DATA_VALUE);
67 if (set->flags & NFT_SET_MAP)
68 nft_data_uninit(he->data, set->dtype);
69 kfree(he);
70}
71
72static int nft_hash_insert(const struct nft_set *set,
73 const struct nft_set_elem *elem)
74{
75 struct nft_hash *priv = nft_set_priv(set);
76 struct nft_hash_elem *he;
77 unsigned int size, h;
78
79 if (elem->flags != 0)
80 return -EINVAL;
81
82 size = sizeof(*he);
83 if (set->flags & NFT_SET_MAP)
84 size += sizeof(he->data[0]);
85
86 he = kzalloc(size, GFP_KERNEL);
87 if (he == NULL)
88 return -ENOMEM;
89
90 nft_data_copy(&he->key, &elem->key);
91 if (set->flags & NFT_SET_MAP)
92 nft_data_copy(he->data, &elem->data);
93
94 h = nft_hash_data(&he->key, priv->hsize, set->klen);
95 hlist_add_head_rcu(&he->hnode, &priv->hash[h]);
96 return 0;
97}
98
99static void nft_hash_remove(const struct nft_set *set,
100 const struct nft_set_elem *elem)
101{
102 struct nft_hash_elem *he = elem->cookie;
103
104 hlist_del_rcu(&he->hnode);
105 kfree(he);
106}
107
108static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
109{
110 const struct nft_hash *priv = nft_set_priv(set);
111 struct nft_hash_elem *he;
112 unsigned int h;
113
114 h = nft_hash_data(&elem->key, priv->hsize, set->klen);
115 hlist_for_each_entry(he, &priv->hash[h], hnode) {
116 if (nft_data_cmp(&he->key, &elem->key, set->klen))
117 continue;
118
119 elem->cookie = he;
120 elem->flags = 0;
121 if (set->flags & NFT_SET_MAP)
122 nft_data_copy(&elem->data, he->data);
123 return 0;
124 }
125 return -ENOENT;
126}
127
128static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
129 struct nft_set_iter *iter)
130{
131 const struct nft_hash *priv = nft_set_priv(set);
132 const struct nft_hash_elem *he;
133 struct nft_set_elem elem;
134 unsigned int i;
135
136 for (i = 0; i < priv->hsize; i++) {
137 hlist_for_each_entry(he, &priv->hash[i], hnode) {
138 if (iter->count < iter->skip)
139 goto cont;
140
141 memcpy(&elem.key, &he->key, sizeof(elem.key));
142 if (set->flags & NFT_SET_MAP)
143 memcpy(&elem.data, he->data, sizeof(elem.data));
144 elem.flags = 0;
145
146 iter->err = iter->fn(ctx, set, iter, &elem);
147 if (iter->err < 0)
148 return;
149cont:
150 iter->count++;
151 }
152 }
153}
154
155static unsigned int nft_hash_privsize(const struct nlattr * const nla[])
156{
157 return sizeof(struct nft_hash);
158}
159
160static int nft_hash_init(const struct nft_set *set,
161 const struct nlattr * const tb[])
162{
163 struct nft_hash *priv = nft_set_priv(set);
164 unsigned int cnt, i;
165
166 if (unlikely(!nft_hash_rnd_initted)) {
167 get_random_bytes(&nft_hash_rnd, 4);
168 nft_hash_rnd_initted = true;
169 }
170
171 /* Aim for a load factor of 0.75 */
172 // FIXME: temporarily broken until we have set descriptions
173 cnt = 100;
174 cnt = cnt * 4 / 3;
175
176 priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
177 if (priv->hash == NULL)
178 return -ENOMEM;
179 priv->hsize = cnt;
180
181 for (i = 0; i < cnt; i++)
182 INIT_HLIST_HEAD(&priv->hash[i]);
183
184 return 0;
185}
186
187static void nft_hash_destroy(const struct nft_set *set)
188{
189 const struct nft_hash *priv = nft_set_priv(set);
190 const struct hlist_node *next;
191 struct nft_hash_elem *elem;
192 unsigned int i;
193
194 for (i = 0; i < priv->hsize; i++) {
195 hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
196 hlist_del(&elem->hnode);
197 nft_hash_elem_destroy(set, elem);
198 }
199 }
200 kfree(priv->hash);
201}
202
203static struct nft_set_ops nft_hash_ops __read_mostly = {
204 .privsize = nft_hash_privsize,
205 .init = nft_hash_init,
206 .destroy = nft_hash_destroy,
207 .get = nft_hash_get,
208 .insert = nft_hash_insert,
209 .remove = nft_hash_remove,
210 .lookup = nft_hash_lookup,
211 .walk = nft_hash_walk,
212 .features = NFT_SET_MAP,
213 .owner = THIS_MODULE,
214};
215
216static int __init nft_hash_module_init(void)
217{
218 return nft_register_set(&nft_hash_ops);
219}
220
221static void __exit nft_hash_module_exit(void)
222{
223 nft_unregister_set(&nft_hash_ops);
224}
225
226module_init(nft_hash_module_init);
227module_exit(nft_hash_module_exit);
228
229MODULE_LICENSE("GPL");
230MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
231MODULE_ALIAS_NFT_SET();
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
new file mode 100644
index 000000000000..f169501f1ad4
--- /dev/null
+++ b/net/netfilter/nft_immediate.c
@@ -0,0 +1,132 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_immediate_expr {
21 struct nft_data data;
22 enum nft_registers dreg:8;
23 u8 dlen;
24};
25
26static void nft_immediate_eval(const struct nft_expr *expr,
27 struct nft_data data[NFT_REG_MAX + 1],
28 const struct nft_pktinfo *pkt)
29{
30 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
31
32 nft_data_copy(&data[priv->dreg], &priv->data);
33}
34
35static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
36 [NFTA_IMMEDIATE_DREG] = { .type = NLA_U32 },
37 [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED },
38};
39
40static int nft_immediate_init(const struct nft_ctx *ctx,
41 const struct nft_expr *expr,
42 const struct nlattr * const tb[])
43{
44 struct nft_immediate_expr *priv = nft_expr_priv(expr);
45 struct nft_data_desc desc;
46 int err;
47
48 if (tb[NFTA_IMMEDIATE_DREG] == NULL ||
49 tb[NFTA_IMMEDIATE_DATA] == NULL)
50 return -EINVAL;
51
52 priv->dreg = ntohl(nla_get_be32(tb[NFTA_IMMEDIATE_DREG]));
53 err = nft_validate_output_register(priv->dreg);
54 if (err < 0)
55 return err;
56
57 err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
58 if (err < 0)
59 return err;
60 priv->dlen = desc.len;
61
62 err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
63 if (err < 0)
64 goto err1;
65
66 return 0;
67
68err1:
69 nft_data_uninit(&priv->data, desc.type);
70 return err;
71}
72
73static void nft_immediate_destroy(const struct nft_expr *expr)
74{
75 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
76 return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg));
77}
78
79static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
80{
81 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
82
83 if (nla_put_be32(skb, NFTA_IMMEDIATE_DREG, htonl(priv->dreg)))
84 goto nla_put_failure;
85
86 return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
87 nft_dreg_to_type(priv->dreg), priv->dlen);
88
89nla_put_failure:
90 return -1;
91}
92
93static int nft_immediate_validate(const struct nft_ctx *ctx,
94 const struct nft_expr *expr,
95 const struct nft_data **data)
96{
97 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
98
99 if (priv->dreg == NFT_REG_VERDICT)
100 *data = &priv->data;
101
102 return 0;
103}
104
105static struct nft_expr_type nft_imm_type;
106static const struct nft_expr_ops nft_imm_ops = {
107 .type = &nft_imm_type,
108 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
109 .eval = nft_immediate_eval,
110 .init = nft_immediate_init,
111 .destroy = nft_immediate_destroy,
112 .dump = nft_immediate_dump,
113 .validate = nft_immediate_validate,
114};
115
116static struct nft_expr_type nft_imm_type __read_mostly = {
117 .name = "immediate",
118 .ops = &nft_imm_ops,
119 .policy = nft_immediate_policy,
120 .maxattr = NFTA_IMMEDIATE_MAX,
121 .owner = THIS_MODULE,
122};
123
124int __init nft_immediate_module_init(void)
125{
126 return nft_register_expr(&nft_imm_type);
127}
128
129void nft_immediate_module_exit(void)
130{
131 nft_unregister_expr(&nft_imm_type);
132}
diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c
new file mode 100644
index 000000000000..85da5bd02f64
--- /dev/null
+++ b/net/netfilter/nft_limit.c
@@ -0,0 +1,119 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/spinlock.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20static DEFINE_SPINLOCK(limit_lock);
21
22struct nft_limit {
23 u64 tokens;
24 u64 rate;
25 u64 unit;
26 unsigned long stamp;
27};
28
29static void nft_limit_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 struct nft_limit *priv = nft_expr_priv(expr);
34
35 spin_lock_bh(&limit_lock);
36 if (time_after_eq(jiffies, priv->stamp)) {
37 priv->tokens = priv->rate;
38 priv->stamp = jiffies + priv->unit * HZ;
39 }
40
41 if (priv->tokens >= 1) {
42 priv->tokens--;
43 spin_unlock_bh(&limit_lock);
44 return;
45 }
46 spin_unlock_bh(&limit_lock);
47
48 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
49}
50
51static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
52 [NFTA_LIMIT_RATE] = { .type = NLA_U64 },
53 [NFTA_LIMIT_UNIT] = { .type = NLA_U64 },
54};
55
56static int nft_limit_init(const struct nft_ctx *ctx,
57 const struct nft_expr *expr,
58 const struct nlattr * const tb[])
59{
60 struct nft_limit *priv = nft_expr_priv(expr);
61
62 if (tb[NFTA_LIMIT_RATE] == NULL ||
63 tb[NFTA_LIMIT_UNIT] == NULL)
64 return -EINVAL;
65
66 priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
67 priv->unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
68 priv->stamp = jiffies + priv->unit * HZ;
69 priv->tokens = priv->rate;
70 return 0;
71}
72
73static int nft_limit_dump(struct sk_buff *skb, const struct nft_expr *expr)
74{
75 const struct nft_limit *priv = nft_expr_priv(expr);
76
77 if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(priv->rate)))
78 goto nla_put_failure;
79 if (nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(priv->unit)))
80 goto nla_put_failure;
81 return 0;
82
83nla_put_failure:
84 return -1;
85}
86
87static struct nft_expr_type nft_limit_type;
88static const struct nft_expr_ops nft_limit_ops = {
89 .type = &nft_limit_type,
90 .size = NFT_EXPR_SIZE(sizeof(struct nft_limit)),
91 .eval = nft_limit_eval,
92 .init = nft_limit_init,
93 .dump = nft_limit_dump,
94};
95
96static struct nft_expr_type nft_limit_type __read_mostly = {
97 .name = "limit",
98 .ops = &nft_limit_ops,
99 .policy = nft_limit_policy,
100 .maxattr = NFTA_LIMIT_MAX,
101 .owner = THIS_MODULE,
102};
103
104static int __init nft_limit_module_init(void)
105{
106 return nft_register_expr(&nft_limit_type);
107}
108
109static void __exit nft_limit_module_exit(void)
110{
111 nft_unregister_expr(&nft_limit_type);
112}
113
114module_init(nft_limit_module_init);
115module_exit(nft_limit_module_exit);
116
117MODULE_LICENSE("GPL");
118MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
119MODULE_ALIAS_NFT_EXPR("limit");
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c
new file mode 100644
index 000000000000..57cad072a13e
--- /dev/null
+++ b/net/netfilter/nft_log.c
@@ -0,0 +1,146 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18#include <net/netfilter/nf_log.h>
19#include <linux/netdevice.h>
20
21static const char *nft_log_null_prefix = "";
22
23struct nft_log {
24 struct nf_loginfo loginfo;
25 char *prefix;
26 int family;
27};
28
29static void nft_log_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 const struct nft_log *priv = nft_expr_priv(expr);
34 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
35
36 nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in,
37 pkt->out, &priv->loginfo, "%s", priv->prefix);
38}
39
40static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
41 [NFTA_LOG_GROUP] = { .type = NLA_U16 },
42 [NFTA_LOG_PREFIX] = { .type = NLA_STRING },
43 [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 },
44 [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 },
45};
46
47static int nft_log_init(const struct nft_ctx *ctx,
48 const struct nft_expr *expr,
49 const struct nlattr * const tb[])
50{
51 struct nft_log *priv = nft_expr_priv(expr);
52 struct nf_loginfo *li = &priv->loginfo;
53 const struct nlattr *nla;
54
55 priv->family = ctx->afi->family;
56
57 nla = tb[NFTA_LOG_PREFIX];
58 if (nla != NULL) {
59 priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
60 if (priv->prefix == NULL)
61 return -ENOMEM;
62 nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
63 } else
64 priv->prefix = (char *)nft_log_null_prefix;
65
66 li->type = NF_LOG_TYPE_ULOG;
67 if (tb[NFTA_LOG_GROUP] != NULL)
68 li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
69
70 if (tb[NFTA_LOG_SNAPLEN] != NULL)
71 li->u.ulog.copy_len = ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
72 if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
73 li->u.ulog.qthreshold =
74 ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
75 }
76
77 return 0;
78}
79
80static void nft_log_destroy(const struct nft_expr *expr)
81{
82 struct nft_log *priv = nft_expr_priv(expr);
83
84 if (priv->prefix != nft_log_null_prefix)
85 kfree(priv->prefix);
86}
87
88static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
89{
90 const struct nft_log *priv = nft_expr_priv(expr);
91 const struct nf_loginfo *li = &priv->loginfo;
92
93 if (priv->prefix != nft_log_null_prefix)
94 if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
95 goto nla_put_failure;
96 if (li->u.ulog.group)
97 if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
98 goto nla_put_failure;
99 if (li->u.ulog.copy_len)
100 if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
101 htonl(li->u.ulog.copy_len)))
102 goto nla_put_failure;
103 if (li->u.ulog.qthreshold)
104 if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
105 htons(li->u.ulog.qthreshold)))
106 goto nla_put_failure;
107 return 0;
108
109nla_put_failure:
110 return -1;
111}
112
113static struct nft_expr_type nft_log_type;
114static const struct nft_expr_ops nft_log_ops = {
115 .type = &nft_log_type,
116 .size = NFT_EXPR_SIZE(sizeof(struct nft_log)),
117 .eval = nft_log_eval,
118 .init = nft_log_init,
119 .destroy = nft_log_destroy,
120 .dump = nft_log_dump,
121};
122
123static struct nft_expr_type nft_log_type __read_mostly = {
124 .name = "log",
125 .ops = &nft_log_ops,
126 .policy = nft_log_policy,
127 .maxattr = NFTA_LOG_MAX,
128 .owner = THIS_MODULE,
129};
130
131static int __init nft_log_module_init(void)
132{
133 return nft_register_expr(&nft_log_type);
134}
135
136static void __exit nft_log_module_exit(void)
137{
138 nft_unregister_expr(&nft_log_type);
139}
140
141module_init(nft_log_module_init);
142module_exit(nft_log_module_exit);
143
144MODULE_LICENSE("GPL");
145MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
146MODULE_ALIAS_NFT_EXPR("log");
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
new file mode 100644
index 000000000000..8a6116b75b5a
--- /dev/null
+++ b/net/netfilter/nft_lookup.c
@@ -0,0 +1,141 @@
1/*
2 * Copyright (c) 2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/rbtree.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_lookup {
21 struct nft_set *set;
22 enum nft_registers sreg:8;
23 enum nft_registers dreg:8;
24 struct nft_set_binding binding;
25};
26
27static void nft_lookup_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_lookup *priv = nft_expr_priv(expr);
32 const struct nft_set *set = priv->set;
33
34 if (set->ops->lookup(set, &data[priv->sreg], &data[priv->dreg]))
35 return;
36 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
37}
38
39static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
40 [NFTA_LOOKUP_SET] = { .type = NLA_STRING },
41 [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
42 [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
43};
44
45static int nft_lookup_init(const struct nft_ctx *ctx,
46 const struct nft_expr *expr,
47 const struct nlattr * const tb[])
48{
49 struct nft_lookup *priv = nft_expr_priv(expr);
50 struct nft_set *set;
51 int err;
52
53 if (tb[NFTA_LOOKUP_SET] == NULL ||
54 tb[NFTA_LOOKUP_SREG] == NULL)
55 return -EINVAL;
56
57 set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]);
58 if (IS_ERR(set))
59 return PTR_ERR(set);
60
61 priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
62 err = nft_validate_input_register(priv->sreg);
63 if (err < 0)
64 return err;
65
66 if (tb[NFTA_LOOKUP_DREG] != NULL) {
67 if (!(set->flags & NFT_SET_MAP))
68 return -EINVAL;
69
70 priv->dreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_DREG]));
71 err = nft_validate_output_register(priv->dreg);
72 if (err < 0)
73 return err;
74
75 if (priv->dreg == NFT_REG_VERDICT) {
76 if (set->dtype != NFT_DATA_VERDICT)
77 return -EINVAL;
78 } else if (set->dtype == NFT_DATA_VERDICT)
79 return -EINVAL;
80 } else if (set->flags & NFT_SET_MAP)
81 return -EINVAL;
82
83 err = nf_tables_bind_set(ctx, set, &priv->binding);
84 if (err < 0)
85 return err;
86
87 priv->set = set;
88 return 0;
89}
90
91static void nft_lookup_destroy(const struct nft_expr *expr)
92{
93 struct nft_lookup *priv = nft_expr_priv(expr);
94
95 nf_tables_unbind_set(NULL, priv->set, &priv->binding);
96}
97
98static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
99{
100 const struct nft_lookup *priv = nft_expr_priv(expr);
101
102 if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
103 goto nla_put_failure;
104 if (nla_put_be32(skb, NFTA_LOOKUP_SREG, htonl(priv->sreg)))
105 goto nla_put_failure;
106 if (priv->set->flags & NFT_SET_MAP)
107 if (nla_put_be32(skb, NFTA_LOOKUP_DREG, htonl(priv->dreg)))
108 goto nla_put_failure;
109 return 0;
110
111nla_put_failure:
112 return -1;
113}
114
115static struct nft_expr_type nft_lookup_type;
116static const struct nft_expr_ops nft_lookup_ops = {
117 .type = &nft_lookup_type,
118 .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
119 .eval = nft_lookup_eval,
120 .init = nft_lookup_init,
121 .destroy = nft_lookup_destroy,
122 .dump = nft_lookup_dump,
123};
124
125static struct nft_expr_type nft_lookup_type __read_mostly = {
126 .name = "lookup",
127 .ops = &nft_lookup_ops,
128 .policy = nft_lookup_policy,
129 .maxattr = NFTA_LOOKUP_MAX,
130 .owner = THIS_MODULE,
131};
132
133int __init nft_lookup_module_init(void)
134{
135 return nft_register_expr(&nft_lookup_type);
136}
137
138void nft_lookup_module_exit(void)
139{
140 nft_unregister_expr(&nft_lookup_type);
141}
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
new file mode 100644
index 000000000000..8c28220a90b3
--- /dev/null
+++ b/net/netfilter/nft_meta.c
@@ -0,0 +1,228 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/dst.h>
18#include <net/sock.h>
19#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
20#include <net/netfilter/nf_tables.h>
21
22struct nft_meta {
23 enum nft_meta_keys key:8;
24 enum nft_registers dreg:8;
25};
26
27static void nft_meta_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_meta *priv = nft_expr_priv(expr);
32 const struct sk_buff *skb = pkt->skb;
33 const struct net_device *in = pkt->in, *out = pkt->out;
34 struct nft_data *dest = &data[priv->dreg];
35
36 switch (priv->key) {
37 case NFT_META_LEN:
38 dest->data[0] = skb->len;
39 break;
40 case NFT_META_PROTOCOL:
41 *(__be16 *)dest->data = skb->protocol;
42 break;
43 case NFT_META_PRIORITY:
44 dest->data[0] = skb->priority;
45 break;
46 case NFT_META_MARK:
47 dest->data[0] = skb->mark;
48 break;
49 case NFT_META_IIF:
50 if (in == NULL)
51 goto err;
52 dest->data[0] = in->ifindex;
53 break;
54 case NFT_META_OIF:
55 if (out == NULL)
56 goto err;
57 dest->data[0] = out->ifindex;
58 break;
59 case NFT_META_IIFNAME:
60 if (in == NULL)
61 goto err;
62 strncpy((char *)dest->data, in->name, sizeof(dest->data));
63 break;
64 case NFT_META_OIFNAME:
65 if (out == NULL)
66 goto err;
67 strncpy((char *)dest->data, out->name, sizeof(dest->data));
68 break;
69 case NFT_META_IIFTYPE:
70 if (in == NULL)
71 goto err;
72 *(u16 *)dest->data = in->type;
73 break;
74 case NFT_META_OIFTYPE:
75 if (out == NULL)
76 goto err;
77 *(u16 *)dest->data = out->type;
78 break;
79 case NFT_META_SKUID:
80 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
81 goto err;
82
83 read_lock_bh(&skb->sk->sk_callback_lock);
84 if (skb->sk->sk_socket == NULL ||
85 skb->sk->sk_socket->file == NULL) {
86 read_unlock_bh(&skb->sk->sk_callback_lock);
87 goto err;
88 }
89
90 dest->data[0] =
91 from_kuid_munged(&init_user_ns,
92 skb->sk->sk_socket->file->f_cred->fsuid);
93 read_unlock_bh(&skb->sk->sk_callback_lock);
94 break;
95 case NFT_META_SKGID:
96 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
97 goto err;
98
99 read_lock_bh(&skb->sk->sk_callback_lock);
100 if (skb->sk->sk_socket == NULL ||
101 skb->sk->sk_socket->file == NULL) {
102 read_unlock_bh(&skb->sk->sk_callback_lock);
103 goto err;
104 }
105 dest->data[0] =
106 from_kgid_munged(&init_user_ns,
107 skb->sk->sk_socket->file->f_cred->fsgid);
108 read_unlock_bh(&skb->sk->sk_callback_lock);
109 break;
110#ifdef CONFIG_NET_CLS_ROUTE
111 case NFT_META_RTCLASSID: {
112 const struct dst_entry *dst = skb_dst(skb);
113
114 if (dst == NULL)
115 goto err;
116 dest->data[0] = dst->tclassid;
117 break;
118 }
119#endif
120#ifdef CONFIG_NETWORK_SECMARK
121 case NFT_META_SECMARK:
122 dest->data[0] = skb->secmark;
123 break;
124#endif
125 default:
126 WARN_ON(1);
127 goto err;
128 }
129 return;
130
131err:
132 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
133}
134
135static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
136 [NFTA_META_DREG] = { .type = NLA_U32 },
137 [NFTA_META_KEY] = { .type = NLA_U32 },
138};
139
140static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
141 const struct nlattr * const tb[])
142{
143 struct nft_meta *priv = nft_expr_priv(expr);
144 int err;
145
146 if (tb[NFTA_META_DREG] == NULL ||
147 tb[NFTA_META_KEY] == NULL)
148 return -EINVAL;
149
150 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
151 switch (priv->key) {
152 case NFT_META_LEN:
153 case NFT_META_PROTOCOL:
154 case NFT_META_PRIORITY:
155 case NFT_META_MARK:
156 case NFT_META_IIF:
157 case NFT_META_OIF:
158 case NFT_META_IIFNAME:
159 case NFT_META_OIFNAME:
160 case NFT_META_IIFTYPE:
161 case NFT_META_OIFTYPE:
162 case NFT_META_SKUID:
163 case NFT_META_SKGID:
164#ifdef CONFIG_NET_CLS_ROUTE
165 case NFT_META_RTCLASSID:
166#endif
167#ifdef CONFIG_NETWORK_SECMARK
168 case NFT_META_SECMARK:
169#endif
170 break;
171 default:
172 return -EOPNOTSUPP;
173 }
174
175 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
176 err = nft_validate_output_register(priv->dreg);
177 if (err < 0)
178 return err;
179 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
180}
181
182static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
183{
184 const struct nft_meta *priv = nft_expr_priv(expr);
185
186 if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg)))
187 goto nla_put_failure;
188 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
189 goto nla_put_failure;
190 return 0;
191
192nla_put_failure:
193 return -1;
194}
195
196static struct nft_expr_type nft_meta_type;
197static const struct nft_expr_ops nft_meta_ops = {
198 .type = &nft_meta_type,
199 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
200 .eval = nft_meta_eval,
201 .init = nft_meta_init,
202 .dump = nft_meta_dump,
203};
204
205static struct nft_expr_type nft_meta_type __read_mostly = {
206 .name = "meta",
207 .ops = &nft_meta_ops,
208 .policy = nft_meta_policy,
209 .maxattr = NFTA_META_MAX,
210 .owner = THIS_MODULE,
211};
212
213static int __init nft_meta_module_init(void)
214{
215 return nft_register_expr(&nft_meta_type);
216}
217
218static void __exit nft_meta_module_exit(void)
219{
220 nft_unregister_expr(&nft_meta_type);
221}
222
223module_init(nft_meta_module_init);
224module_exit(nft_meta_module_exit);
225
226MODULE_LICENSE("GPL");
227MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
228MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_meta_target.c b/net/netfilter/nft_meta_target.c
new file mode 100644
index 000000000000..71177df75ffb
--- /dev/null
+++ b/net/netfilter/nft_meta_target.c
@@ -0,0 +1,117 @@
1/*
2 * Copyright (c) 2008 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/rbtree.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_meta {
21 enum nft_meta_keys key;
22};
23
24static void nft_meta_eval(const struct nft_expr *expr,
25 struct nft_data *nfres,
26 struct nft_data *data,
27 const struct nft_pktinfo *pkt)
28{
29 const struct nft_meta *meta = nft_expr_priv(expr);
30 struct sk_buff *skb = pkt->skb;
31 u32 val = data->data[0];
32
33 switch (meta->key) {
34 case NFT_META_MARK:
35 skb->mark = val;
36 break;
37 case NFT_META_PRIORITY:
38 skb->priority = val;
39 break;
40 case NFT_META_NFTRACE:
41 skb->nf_trace = val;
42 break;
43#ifdef CONFIG_NETWORK_SECMARK
44 case NFT_META_SECMARK:
45 skb->secmark = val;
46 break;
47#endif
48 default:
49 WARN_ON(1);
50 }
51}
52
53static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
54 [NFTA_META_KEY] = { .type = NLA_U32 },
55};
56
57static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[])
58{
59 struct nft_meta *meta = nft_expr_priv(expr);
60
61 if (tb[NFTA_META_KEY] == NULL)
62 return -EINVAL;
63
64 meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
65 switch (meta->key) {
66 case NFT_META_MARK:
67 case NFT_META_PRIORITY:
68 case NFT_META_NFTRACE:
69#ifdef CONFIG_NETWORK_SECMARK
70 case NFT_META_SECMARK:
71#endif
72 break;
73 default:
74 return -EINVAL;
75 }
76
77 return 0;
78}
79
80static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
81{
82 struct nft_meta *meta = nft_expr_priv(expr);
83
84 NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key));
85 return 0;
86
87nla_put_failure:
88 return -1;
89}
90
91static struct nft_expr_ops meta_target __read_mostly = {
92 .name = "meta",
93 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
94 .owner = THIS_MODULE,
95 .eval = nft_meta_eval,
96 .init = nft_meta_init,
97 .dump = nft_meta_dump,
98 .policy = nft_meta_policy,
99 .maxattr = NFTA_META_MAX,
100};
101
102static int __init nft_meta_target_init(void)
103{
104 return nft_register_expr(&meta_target);
105}
106
107static void __exit nft_meta_target_exit(void)
108{
109 nft_unregister_expr(&meta_target);
110}
111
112module_init(nft_meta_target_init);
113module_exit(nft_meta_target_exit);
114
115MODULE_LICENSE("GPL");
116MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
117MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
new file mode 100644
index 000000000000..b0b87b2d2411
--- /dev/null
+++ b/net/netfilter/nft_nat.c
@@ -0,0 +1,220 @@
1/*
2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4 * Copyright (c) 2012 Intel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/skbuff.h>
15#include <linux/ip.h>
16#include <linux/string.h>
17#include <linux/netlink.h>
18#include <linux/netfilter.h>
19#include <linux/netfilter_ipv4.h>
20#include <linux/netfilter/nfnetlink.h>
21#include <linux/netfilter/nf_tables.h>
22#include <net/netfilter/nf_conntrack.h>
23#include <net/netfilter/nf_nat.h>
24#include <net/netfilter/nf_nat_core.h>
25#include <net/netfilter/nf_tables.h>
26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/ip.h>
28
29struct nft_nat {
30 enum nft_registers sreg_addr_min:8;
31 enum nft_registers sreg_addr_max:8;
32 enum nft_registers sreg_proto_min:8;
33 enum nft_registers sreg_proto_max:8;
34 int family;
35 enum nf_nat_manip_type type;
36};
37
38static void nft_nat_eval(const struct nft_expr *expr,
39 struct nft_data data[NFT_REG_MAX + 1],
40 const struct nft_pktinfo *pkt)
41{
42 const struct nft_nat *priv = nft_expr_priv(expr);
43 enum ip_conntrack_info ctinfo;
44 struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
45 struct nf_nat_range range;
46
47 memset(&range, 0, sizeof(range));
48 if (priv->sreg_addr_min) {
49 if (priv->family == AF_INET) {
50 range.min_addr.ip = data[priv->sreg_addr_min].data[0];
51 range.max_addr.ip = data[priv->sreg_addr_max].data[0];
52
53 } else {
54 memcpy(range.min_addr.ip6,
55 data[priv->sreg_addr_min].data,
56 sizeof(struct nft_data));
57 memcpy(range.max_addr.ip6,
58 data[priv->sreg_addr_max].data,
59 sizeof(struct nft_data));
60 }
61 range.flags |= NF_NAT_RANGE_MAP_IPS;
62 }
63
64 if (priv->sreg_proto_min) {
65 range.min_proto.all = data[priv->sreg_proto_min].data[0];
66 range.max_proto.all = data[priv->sreg_proto_max].data[0];
67 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
68 }
69
70 data[NFT_REG_VERDICT].verdict =
71 nf_nat_setup_info(ct, &range, priv->type);
72}
73
74static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
75 [NFTA_NAT_TYPE] = { .type = NLA_U32 },
76 [NFTA_NAT_FAMILY] = { .type = NLA_U32 },
77 [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 },
78 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 },
79 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
80 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
81};
82
83static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
84 const struct nlattr * const tb[])
85{
86 struct nft_nat *priv = nft_expr_priv(expr);
87 int err;
88
89 if (tb[NFTA_NAT_TYPE] == NULL)
90 return -EINVAL;
91
92 switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
93 case NFT_NAT_SNAT:
94 priv->type = NF_NAT_MANIP_SRC;
95 break;
96 case NFT_NAT_DNAT:
97 priv->type = NF_NAT_MANIP_DST;
98 break;
99 default:
100 return -EINVAL;
101 }
102
103 if (tb[NFTA_NAT_FAMILY] == NULL)
104 return -EINVAL;
105
106 priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
107 if (priv->family != AF_INET && priv->family != AF_INET6)
108 return -EINVAL;
109
110 if (tb[NFTA_NAT_REG_ADDR_MIN]) {
111 priv->sreg_addr_min = ntohl(nla_get_be32(
112 tb[NFTA_NAT_REG_ADDR_MIN]));
113 err = nft_validate_input_register(priv->sreg_addr_min);
114 if (err < 0)
115 return err;
116 }
117
118 if (tb[NFTA_NAT_REG_ADDR_MAX]) {
119 priv->sreg_addr_max = ntohl(nla_get_be32(
120 tb[NFTA_NAT_REG_ADDR_MAX]));
121 err = nft_validate_input_register(priv->sreg_addr_max);
122 if (err < 0)
123 return err;
124 } else
125 priv->sreg_addr_max = priv->sreg_addr_min;
126
127 if (tb[NFTA_NAT_REG_PROTO_MIN]) {
128 priv->sreg_proto_min = ntohl(nla_get_be32(
129 tb[NFTA_NAT_REG_PROTO_MIN]));
130 err = nft_validate_input_register(priv->sreg_proto_min);
131 if (err < 0)
132 return err;
133 }
134
135 if (tb[NFTA_NAT_REG_PROTO_MAX]) {
136 priv->sreg_proto_max = ntohl(nla_get_be32(
137 tb[NFTA_NAT_REG_PROTO_MAX]));
138 err = nft_validate_input_register(priv->sreg_proto_max);
139 if (err < 0)
140 return err;
141 } else
142 priv->sreg_proto_max = priv->sreg_proto_min;
143
144 return 0;
145}
146
147static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
148{
149 const struct nft_nat *priv = nft_expr_priv(expr);
150
151 switch (priv->type) {
152 case NF_NAT_MANIP_SRC:
153 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
154 goto nla_put_failure;
155 break;
156 case NF_NAT_MANIP_DST:
157 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
158 goto nla_put_failure;
159 break;
160 }
161
162 if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
163 goto nla_put_failure;
164 if (nla_put_be32(skb,
165 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
166 goto nla_put_failure;
167 if (nla_put_be32(skb,
168 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
169 goto nla_put_failure;
170 if (nla_put_be32(skb,
171 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
172 goto nla_put_failure;
173 if (nla_put_be32(skb,
174 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
175 goto nla_put_failure;
176 return 0;
177
178nla_put_failure:
179 return -1;
180}
181
182static struct nft_expr_type nft_nat_type;
183static const struct nft_expr_ops nft_nat_ops = {
184 .type = &nft_nat_type,
185 .size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
186 .eval = nft_nat_eval,
187 .init = nft_nat_init,
188 .dump = nft_nat_dump,
189};
190
191static struct nft_expr_type nft_nat_type __read_mostly = {
192 .name = "nat",
193 .ops = &nft_nat_ops,
194 .policy = nft_nat_policy,
195 .maxattr = NFTA_NAT_MAX,
196 .owner = THIS_MODULE,
197};
198
199static int __init nft_nat_module_init(void)
200{
201 int err;
202
203 err = nft_register_expr(&nft_nat_type);
204 if (err < 0)
205 return err;
206
207 return 0;
208}
209
210static void __exit nft_nat_module_exit(void)
211{
212 nft_unregister_expr(&nft_nat_type);
213}
214
215module_init(nft_nat_module_init);
216module_exit(nft_nat_module_exit);
217
218MODULE_LICENSE("GPL");
219MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
220MODULE_ALIAS_NFT_EXPR("nat");
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
new file mode 100644
index 000000000000..a2aeb318678f
--- /dev/null
+++ b/net/netfilter/nft_payload.c
@@ -0,0 +1,160 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20static void nft_payload_eval(const struct nft_expr *expr,
21 struct nft_data data[NFT_REG_MAX + 1],
22 const struct nft_pktinfo *pkt)
23{
24 const struct nft_payload *priv = nft_expr_priv(expr);
25 const struct sk_buff *skb = pkt->skb;
26 struct nft_data *dest = &data[priv->dreg];
27 int offset;
28
29 switch (priv->base) {
30 case NFT_PAYLOAD_LL_HEADER:
31 if (!skb_mac_header_was_set(skb))
32 goto err;
33 offset = skb_mac_header(skb) - skb->data;
34 break;
35 case NFT_PAYLOAD_NETWORK_HEADER:
36 offset = skb_network_offset(skb);
37 break;
38 case NFT_PAYLOAD_TRANSPORT_HEADER:
39 offset = pkt->xt.thoff;
40 break;
41 default:
42 BUG();
43 }
44 offset += priv->offset;
45
46 if (skb_copy_bits(skb, offset, dest->data, priv->len) < 0)
47 goto err;
48 return;
49err:
50 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
51}
52
53static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
54 [NFTA_PAYLOAD_DREG] = { .type = NLA_U32 },
55 [NFTA_PAYLOAD_BASE] = { .type = NLA_U32 },
56 [NFTA_PAYLOAD_OFFSET] = { .type = NLA_U32 },
57 [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 },
58};
59
60static int nft_payload_init(const struct nft_ctx *ctx,
61 const struct nft_expr *expr,
62 const struct nlattr * const tb[])
63{
64 struct nft_payload *priv = nft_expr_priv(expr);
65 int err;
66
67 priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
68 priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
69 priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
70
71 priv->dreg = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_DREG]));
72 err = nft_validate_output_register(priv->dreg);
73 if (err < 0)
74 return err;
75 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
76}
77
78static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
79{
80 const struct nft_payload *priv = nft_expr_priv(expr);
81
82 if (nla_put_be32(skb, NFTA_PAYLOAD_DREG, htonl(priv->dreg)) ||
83 nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
84 nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
85 nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
86 goto nla_put_failure;
87 return 0;
88
89nla_put_failure:
90 return -1;
91}
92
93static struct nft_expr_type nft_payload_type;
94static const struct nft_expr_ops nft_payload_ops = {
95 .type = &nft_payload_type,
96 .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
97 .eval = nft_payload_eval,
98 .init = nft_payload_init,
99 .dump = nft_payload_dump,
100};
101
102const struct nft_expr_ops nft_payload_fast_ops = {
103 .type = &nft_payload_type,
104 .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
105 .eval = nft_payload_eval,
106 .init = nft_payload_init,
107 .dump = nft_payload_dump,
108};
109
110static const struct nft_expr_ops *
111nft_payload_select_ops(const struct nft_ctx *ctx,
112 const struct nlattr * const tb[])
113{
114 enum nft_payload_bases base;
115 unsigned int offset, len;
116
117 if (tb[NFTA_PAYLOAD_DREG] == NULL ||
118 tb[NFTA_PAYLOAD_BASE] == NULL ||
119 tb[NFTA_PAYLOAD_OFFSET] == NULL ||
120 tb[NFTA_PAYLOAD_LEN] == NULL)
121 return ERR_PTR(-EINVAL);
122
123 base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
124 switch (base) {
125 case NFT_PAYLOAD_LL_HEADER:
126 case NFT_PAYLOAD_NETWORK_HEADER:
127 case NFT_PAYLOAD_TRANSPORT_HEADER:
128 break;
129 default:
130 return ERR_PTR(-EOPNOTSUPP);
131 }
132
133 offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
134 len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
135 if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
136 return ERR_PTR(-EINVAL);
137
138 if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
139 return &nft_payload_fast_ops;
140 else
141 return &nft_payload_ops;
142}
143
144static struct nft_expr_type nft_payload_type __read_mostly = {
145 .name = "payload",
146 .select_ops = nft_payload_select_ops,
147 .policy = nft_payload_policy,
148 .maxattr = NFTA_PAYLOAD_MAX,
149 .owner = THIS_MODULE,
150};
151
152int __init nft_payload_module_init(void)
153{
154 return nft_register_expr(&nft_payload_type);
155}
156
157void nft_payload_module_exit(void)
158{
159 nft_unregister_expr(&nft_payload_type);
160}
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c
new file mode 100644
index 000000000000..ca0c1b231bfe
--- /dev/null
+++ b/net/netfilter/nft_rbtree.c
@@ -0,0 +1,247 @@
1/*
2 * Copyright (c) 2008-2009 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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/list.h>
15#include <linux/rbtree.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_rbtree {
22 struct rb_root root;
23};
24
25struct nft_rbtree_elem {
26 struct rb_node node;
27 u16 flags;
28 struct nft_data key;
29 struct nft_data data[];
30};
31
32static bool nft_rbtree_lookup(const struct nft_set *set,
33 const struct nft_data *key,
34 struct nft_data *data)
35{
36 const struct nft_rbtree *priv = nft_set_priv(set);
37 const struct nft_rbtree_elem *rbe, *interval = NULL;
38 const struct rb_node *parent = priv->root.rb_node;
39 int d;
40
41 while (parent != NULL) {
42 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
43
44 d = nft_data_cmp(&rbe->key, key, set->klen);
45 if (d < 0) {
46 parent = parent->rb_left;
47 interval = rbe;
48 } else if (d > 0)
49 parent = parent->rb_right;
50 else {
51found:
52 if (rbe->flags & NFT_SET_ELEM_INTERVAL_END)
53 goto out;
54 if (set->flags & NFT_SET_MAP)
55 nft_data_copy(data, rbe->data);
56 return true;
57 }
58 }
59
60 if (set->flags & NFT_SET_INTERVAL && interval != NULL) {
61 rbe = interval;
62 goto found;
63 }
64out:
65 return false;
66}
67
68static void nft_rbtree_elem_destroy(const struct nft_set *set,
69 struct nft_rbtree_elem *rbe)
70{
71 nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
72 if (set->flags & NFT_SET_MAP)
73 nft_data_uninit(rbe->data, set->dtype);
74 kfree(rbe);
75}
76
77static int __nft_rbtree_insert(const struct nft_set *set,
78 struct nft_rbtree_elem *new)
79{
80 struct nft_rbtree *priv = nft_set_priv(set);
81 struct nft_rbtree_elem *rbe;
82 struct rb_node *parent, **p;
83 int d;
84
85 parent = NULL;
86 p = &priv->root.rb_node;
87 while (*p != NULL) {
88 parent = *p;
89 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
90 d = nft_data_cmp(&rbe->key, &new->key, set->klen);
91 if (d < 0)
92 p = &parent->rb_left;
93 else if (d > 0)
94 p = &parent->rb_right;
95 else
96 return -EEXIST;
97 }
98 rb_link_node(&new->node, parent, p);
99 rb_insert_color(&new->node, &priv->root);
100 return 0;
101}
102
103static int nft_rbtree_insert(const struct nft_set *set,
104 const struct nft_set_elem *elem)
105{
106 struct nft_rbtree_elem *rbe;
107 unsigned int size;
108 int err;
109
110 size = sizeof(*rbe);
111 if (set->flags & NFT_SET_MAP)
112 size += sizeof(rbe->data[0]);
113
114 rbe = kzalloc(size, GFP_KERNEL);
115 if (rbe == NULL)
116 return -ENOMEM;
117
118 rbe->flags = elem->flags;
119 nft_data_copy(&rbe->key, &elem->key);
120 if (set->flags & NFT_SET_MAP)
121 nft_data_copy(rbe->data, &elem->data);
122
123 err = __nft_rbtree_insert(set, rbe);
124 if (err < 0)
125 kfree(rbe);
126 return err;
127}
128
129static void nft_rbtree_remove(const struct nft_set *set,
130 const struct nft_set_elem *elem)
131{
132 struct nft_rbtree *priv = nft_set_priv(set);
133 struct nft_rbtree_elem *rbe = elem->cookie;
134
135 rb_erase(&rbe->node, &priv->root);
136 kfree(rbe);
137}
138
139static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
140{
141 const struct nft_rbtree *priv = nft_set_priv(set);
142 const struct rb_node *parent = priv->root.rb_node;
143 struct nft_rbtree_elem *rbe;
144 int d;
145
146 while (parent != NULL) {
147 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
148
149 d = nft_data_cmp(&rbe->key, &elem->key, set->klen);
150 if (d < 0)
151 parent = parent->rb_left;
152 else if (d > 0)
153 parent = parent->rb_right;
154 else {
155 elem->cookie = rbe;
156 if (set->flags & NFT_SET_MAP)
157 nft_data_copy(&elem->data, rbe->data);
158 elem->flags = rbe->flags;
159 return 0;
160 }
161 }
162 return -ENOENT;
163}
164
165static void nft_rbtree_walk(const struct nft_ctx *ctx,
166 const struct nft_set *set,
167 struct nft_set_iter *iter)
168{
169 const struct nft_rbtree *priv = nft_set_priv(set);
170 const struct nft_rbtree_elem *rbe;
171 struct nft_set_elem elem;
172 struct rb_node *node;
173
174 for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
175 if (iter->count < iter->skip)
176 goto cont;
177
178 rbe = rb_entry(node, struct nft_rbtree_elem, node);
179 nft_data_copy(&elem.key, &rbe->key);
180 if (set->flags & NFT_SET_MAP)
181 nft_data_copy(&elem.data, rbe->data);
182 elem.flags = rbe->flags;
183
184 iter->err = iter->fn(ctx, set, iter, &elem);
185 if (iter->err < 0)
186 return;
187cont:
188 iter->count++;
189 }
190}
191
192static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[])
193{
194 return sizeof(struct nft_rbtree);
195}
196
197static int nft_rbtree_init(const struct nft_set *set,
198 const struct nlattr * const nla[])
199{
200 struct nft_rbtree *priv = nft_set_priv(set);
201
202 priv->root = RB_ROOT;
203 return 0;
204}
205
206static void nft_rbtree_destroy(const struct nft_set *set)
207{
208 struct nft_rbtree *priv = nft_set_priv(set);
209 struct nft_rbtree_elem *rbe;
210 struct rb_node *node;
211
212 while ((node = priv->root.rb_node) != NULL) {
213 rb_erase(node, &priv->root);
214 rbe = rb_entry(node, struct nft_rbtree_elem, node);
215 nft_rbtree_elem_destroy(set, rbe);
216 }
217}
218
219static struct nft_set_ops nft_rbtree_ops __read_mostly = {
220 .privsize = nft_rbtree_privsize,
221 .init = nft_rbtree_init,
222 .destroy = nft_rbtree_destroy,
223 .insert = nft_rbtree_insert,
224 .remove = nft_rbtree_remove,
225 .get = nft_rbtree_get,
226 .lookup = nft_rbtree_lookup,
227 .walk = nft_rbtree_walk,
228 .features = NFT_SET_INTERVAL | NFT_SET_MAP,
229 .owner = THIS_MODULE,
230};
231
232static int __init nft_rbtree_module_init(void)
233{
234 return nft_register_set(&nft_rbtree_ops);
235}
236
237static void __exit nft_rbtree_module_exit(void)
238{
239 nft_unregister_set(&nft_rbtree_ops);
240}
241
242module_init(nft_rbtree_module_init);
243module_exit(nft_rbtree_module_exit);
244
245MODULE_LICENSE("GPL");
246MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
247MODULE_ALIAS_NFT_SET();