diff options
38 files changed, 636 insertions, 156 deletions
diff --git a/include/net/netfilter/ipv4/nf_nat_redirect.h b/include/net/netfilter/ipv4/nf_nat_redirect.h new file mode 100644 index 000000000000..19e1df3a0a4d --- /dev/null +++ b/include/net/netfilter/ipv4/nf_nat_redirect.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef _NF_NAT_REDIRECT_IPV4_H_ | ||
2 | #define _NF_NAT_REDIRECT_IPV4_H_ | ||
3 | |||
4 | unsigned int | ||
5 | nf_nat_redirect_ipv4(struct sk_buff *skb, | ||
6 | const struct nf_nat_ipv4_multi_range_compat *mr, | ||
7 | unsigned int hooknum); | ||
8 | |||
9 | #endif /* _NF_NAT_REDIRECT_IPV4_H_ */ | ||
diff --git a/include/net/netfilter/ipv6/nf_nat_redirect.h b/include/net/netfilter/ipv6/nf_nat_redirect.h new file mode 100644 index 000000000000..1ebdffc461cc --- /dev/null +++ b/include/net/netfilter/ipv6/nf_nat_redirect.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _NF_NAT_REDIRECT_IPV6_H_ | ||
2 | #define _NF_NAT_REDIRECT_IPV6_H_ | ||
3 | |||
4 | unsigned int | ||
5 | nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, | ||
6 | unsigned int hooknum); | ||
7 | |||
8 | #endif /* _NF_NAT_REDIRECT_IPV6_H_ */ | ||
diff --git a/include/net/netfilter/nft_redir.h b/include/net/netfilter/nft_redir.h new file mode 100644 index 000000000000..a2d67546afab --- /dev/null +++ b/include/net/netfilter/nft_redir.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef _NFT_REDIR_H_ | ||
2 | #define _NFT_REDIR_H_ | ||
3 | |||
4 | struct nft_redir { | ||
5 | enum nft_registers sreg_proto_min:8; | ||
6 | enum nft_registers sreg_proto_max:8; | ||
7 | u16 flags; | ||
8 | }; | ||
9 | |||
10 | extern const struct nla_policy nft_redir_policy[]; | ||
11 | |||
12 | int nft_redir_init(const struct nft_ctx *ctx, | ||
13 | const struct nft_expr *expr, | ||
14 | const struct nlattr * const tb[]); | ||
15 | |||
16 | int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr); | ||
17 | |||
18 | int nft_redir_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
19 | const struct nft_data **data); | ||
20 | |||
21 | #endif /* _NFT_REDIR_H_ */ | ||
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index f31fe7b660a5..832bc46db78b 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -579,6 +579,7 @@ enum nft_exthdr_attributes { | |||
579 | * @NFT_META_CPU: cpu id through smp_processor_id() | 579 | * @NFT_META_CPU: cpu id through smp_processor_id() |
580 | * @NFT_META_IIFGROUP: packet input interface group | 580 | * @NFT_META_IIFGROUP: packet input interface group |
581 | * @NFT_META_OIFGROUP: packet output interface group | 581 | * @NFT_META_OIFGROUP: packet output interface group |
582 | * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) | ||
582 | */ | 583 | */ |
583 | enum nft_meta_keys { | 584 | enum nft_meta_keys { |
584 | NFT_META_LEN, | 585 | NFT_META_LEN, |
@@ -604,6 +605,7 @@ enum nft_meta_keys { | |||
604 | NFT_META_CPU, | 605 | NFT_META_CPU, |
605 | NFT_META_IIFGROUP, | 606 | NFT_META_IIFGROUP, |
606 | NFT_META_OIFGROUP, | 607 | NFT_META_OIFGROUP, |
608 | NFT_META_CGROUP, | ||
607 | }; | 609 | }; |
608 | 610 | ||
609 | /** | 611 | /** |
@@ -838,6 +840,22 @@ enum nft_masq_attributes { | |||
838 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) | 840 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) |
839 | 841 | ||
840 | /** | 842 | /** |
843 | * enum nft_redir_attributes - nf_tables redirect expression netlink attributes | ||
844 | * | ||
845 | * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) | ||
846 | * @NFTA_REDIR_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) | ||
847 | * @NFTA_REDIR_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) | ||
848 | */ | ||
849 | enum nft_redir_attributes { | ||
850 | NFTA_REDIR_UNSPEC, | ||
851 | NFTA_REDIR_REG_PROTO_MIN, | ||
852 | NFTA_REDIR_REG_PROTO_MAX, | ||
853 | NFTA_REDIR_FLAGS, | ||
854 | __NFTA_REDIR_MAX | ||
855 | }; | ||
856 | #define NFTA_REDIR_MAX (__NFTA_REDIR_MAX - 1) | ||
857 | |||
858 | /** | ||
841 | * enum nft_gen_attributes - nf_tables ruleset generation attributes | 859 | * enum nft_gen_attributes - nf_tables ruleset generation attributes |
842 | * | 860 | * |
843 | * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32) | 861 | * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32) |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 1a4f32c09ad5..c190d22b6b3d 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <net/ip.h> | 35 | #include <net/ip.h> |
36 | #include <net/ipv6.h> | 36 | #include <net/ipv6.h> |
37 | #include <net/route.h> | 37 | #include <net/route.h> |
38 | #include <net/netfilter/br_netfilter.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include "br_private.h" | 41 | #include "br_private.h" |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 4c019d5c3f57..8358b2da1549 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -104,6 +104,12 @@ config NF_NAT_MASQUERADE_IPV4 | |||
104 | This is the kernel functionality to provide NAT in the masquerade | 104 | This is the kernel functionality to provide NAT in the masquerade |
105 | flavour (automatic source address selection). | 105 | flavour (automatic source address selection). |
106 | 106 | ||
107 | config NF_NAT_REDIRECT_IPV4 | ||
108 | tristate "IPv4 redirect support" | ||
109 | help | ||
110 | This is the kernel functionality to provide NAT in the redirect | ||
111 | flavour (redirect packets to local machine). | ||
112 | |||
107 | config NFT_MASQ_IPV4 | 113 | config NFT_MASQ_IPV4 |
108 | tristate "IPv4 masquerading support for nf_tables" | 114 | tristate "IPv4 masquerading support for nf_tables" |
109 | depends on NF_TABLES_IPV4 | 115 | depends on NF_TABLES_IPV4 |
@@ -113,6 +119,15 @@ config NFT_MASQ_IPV4 | |||
113 | This is the expression that provides IPv4 masquerading support for | 119 | This is the expression that provides IPv4 masquerading support for |
114 | nf_tables. | 120 | nf_tables. |
115 | 121 | ||
122 | config NFT_REDIR_IPV4 | ||
123 | tristate "IPv4 redirect support for nf_tables" | ||
124 | depends on NF_TABLES_IPV4 | ||
125 | depends on NFT_REDIR | ||
126 | select NF_NAT_REDIRECT_IPV4 | ||
127 | help | ||
128 | This is the expression that provides IPv4 redirect support for | ||
129 | nf_tables. | ||
130 | |||
116 | config NF_NAT_SNMP_BASIC | 131 | config NF_NAT_SNMP_BASIC |
117 | tristate "Basic SNMP-ALG support" | 132 | tristate "Basic SNMP-ALG support" |
118 | depends on NF_CONNTRACK_SNMP | 133 | depends on NF_CONNTRACK_SNMP |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index f4cef5af0969..902bcd1597bb 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o | |||
31 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o | 31 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o |
32 | obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o | 32 | obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o |
33 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o | 33 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o |
34 | obj-$(CONFIG_NF_NAT_REDIRECT_IPV4) += nf_nat_redirect_ipv4.o | ||
34 | 35 | ||
35 | # NAT protocols (nf_nat) | 36 | # NAT protocols (nf_nat) |
36 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o | 37 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o |
@@ -40,6 +41,7 @@ obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o | |||
40 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o | 41 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o |
41 | obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o | 42 | obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o |
42 | obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o | 43 | obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o |
44 | obj-$(CONFIG_NFT_REDIR_IPV4) += nft_redir_ipv4.o | ||
43 | obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o | 45 | obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o |
44 | 46 | ||
45 | # generic IP tables | 47 | # generic IP tables |
diff --git a/net/ipv4/netfilter/nf_log_arp.c b/net/ipv4/netfilter/nf_log_arp.c index ccfc78db12ee..d059182c1466 100644 --- a/net/ipv4/netfilter/nf_log_arp.c +++ b/net/ipv4/netfilter/nf_log_arp.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | 14 | ||
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
15 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
@@ -74,12 +75,12 @@ static void dump_arp_packet(struct nf_log_buf *m, | |||
74 | ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); | 75 | ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); |
75 | } | 76 | } |
76 | 77 | ||
77 | void nf_log_arp_packet(struct net *net, u_int8_t pf, | 78 | static void nf_log_arp_packet(struct net *net, u_int8_t pf, |
78 | unsigned int hooknum, const struct sk_buff *skb, | 79 | unsigned int hooknum, const struct sk_buff *skb, |
79 | const struct net_device *in, | 80 | const struct net_device *in, |
80 | const struct net_device *out, | 81 | const struct net_device *out, |
81 | const struct nf_loginfo *loginfo, | 82 | const struct nf_loginfo *loginfo, |
82 | const char *prefix) | 83 | const char *prefix) |
83 | { | 84 | { |
84 | struct nf_log_buf *m; | 85 | struct nf_log_buf *m; |
85 | 86 | ||
@@ -130,8 +131,17 @@ static int __init nf_log_arp_init(void) | |||
130 | if (ret < 0) | 131 | if (ret < 0) |
131 | return ret; | 132 | return ret; |
132 | 133 | ||
133 | nf_log_register(NFPROTO_ARP, &nf_arp_logger); | 134 | ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger); |
135 | if (ret < 0) { | ||
136 | pr_err("failed to register logger\n"); | ||
137 | goto err1; | ||
138 | } | ||
139 | |||
134 | return 0; | 140 | return 0; |
141 | |||
142 | err1: | ||
143 | unregister_pernet_subsys(&nf_log_arp_net_ops); | ||
144 | return ret; | ||
135 | } | 145 | } |
136 | 146 | ||
137 | static void __exit nf_log_arp_exit(void) | 147 | static void __exit nf_log_arp_exit(void) |
diff --git a/net/ipv4/netfilter/nf_log_ipv4.c b/net/ipv4/netfilter/nf_log_ipv4.c index 078bdca1b607..75101980eeee 100644 --- a/net/ipv4/netfilter/nf_log_ipv4.c +++ b/net/ipv4/netfilter/nf_log_ipv4.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
8 | 9 | ||
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
10 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
@@ -366,8 +367,17 @@ static int __init nf_log_ipv4_init(void) | |||
366 | if (ret < 0) | 367 | if (ret < 0) |
367 | return ret; | 368 | return ret; |
368 | 369 | ||
369 | nf_log_register(NFPROTO_IPV4, &nf_ip_logger); | 370 | ret = nf_log_register(NFPROTO_IPV4, &nf_ip_logger); |
371 | if (ret < 0) { | ||
372 | pr_err("failed to register logger\n"); | ||
373 | goto err1; | ||
374 | } | ||
375 | |||
370 | return 0; | 376 | return 0; |
377 | |||
378 | err1: | ||
379 | unregister_pernet_subsys(&nf_log_ipv4_net_ops); | ||
380 | return ret; | ||
371 | } | 381 | } |
372 | 382 | ||
373 | static void __exit nf_log_ipv4_exit(void) | 383 | static void __exit nf_log_ipv4_exit(void) |
diff --git a/net/ipv4/netfilter/nf_nat_redirect_ipv4.c b/net/ipv4/netfilter/nf_nat_redirect_ipv4.c new file mode 100644 index 000000000000..a220552fc532 --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_redirect_ipv4.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * (C) 1999-2001 Paul `Rusty' Russell | ||
3 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
4 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
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 | * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 | ||
11 | * NAT funded by Astaro. | ||
12 | */ | ||
13 | |||
14 | #include <linux/if.h> | ||
15 | #include <linux/inetdevice.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/netfilter.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/netfilter_ipv4.h> | ||
23 | #include <linux/netfilter/x_tables.h> | ||
24 | #include <net/addrconf.h> | ||
25 | #include <net/checksum.h> | ||
26 | #include <net/protocol.h> | ||
27 | #include <net/netfilter/nf_nat.h> | ||
28 | #include <net/netfilter/ipv4/nf_nat_redirect.h> | ||
29 | |||
30 | unsigned int | ||
31 | nf_nat_redirect_ipv4(struct sk_buff *skb, | ||
32 | const struct nf_nat_ipv4_multi_range_compat *mr, | ||
33 | unsigned int hooknum) | ||
34 | { | ||
35 | struct nf_conn *ct; | ||
36 | enum ip_conntrack_info ctinfo; | ||
37 | __be32 newdst; | ||
38 | struct nf_nat_range newrange; | ||
39 | |||
40 | NF_CT_ASSERT(hooknum == NF_INET_PRE_ROUTING || | ||
41 | hooknum == NF_INET_LOCAL_OUT); | ||
42 | |||
43 | ct = nf_ct_get(skb, &ctinfo); | ||
44 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); | ||
45 | |||
46 | /* Local packets: make them go to loopback */ | ||
47 | if (hooknum == NF_INET_LOCAL_OUT) { | ||
48 | newdst = htonl(0x7F000001); | ||
49 | } else { | ||
50 | struct in_device *indev; | ||
51 | struct in_ifaddr *ifa; | ||
52 | |||
53 | newdst = 0; | ||
54 | |||
55 | rcu_read_lock(); | ||
56 | indev = __in_dev_get_rcu(skb->dev); | ||
57 | if (indev != NULL) { | ||
58 | ifa = indev->ifa_list; | ||
59 | newdst = ifa->ifa_local; | ||
60 | } | ||
61 | rcu_read_unlock(); | ||
62 | |||
63 | if (!newdst) | ||
64 | return NF_DROP; | ||
65 | } | ||
66 | |||
67 | /* Transfer from original range. */ | ||
68 | memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); | ||
69 | memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); | ||
70 | newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; | ||
71 | newrange.min_addr.ip = newdst; | ||
72 | newrange.max_addr.ip = newdst; | ||
73 | newrange.min_proto = mr->range[0].min; | ||
74 | newrange.max_proto = mr->range[0].max; | ||
75 | |||
76 | /* Hand modified range to generic setup. */ | ||
77 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4); | ||
80 | |||
81 | MODULE_LICENSE("GPL"); | ||
82 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 1baaa83dfe5c..536da7bc598a 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <net/tcp.h> | 11 | #include <net/tcp.h> |
12 | #include <net/route.h> | 12 | #include <net/route.h> |
13 | #include <net/dst.h> | 13 | #include <net/dst.h> |
14 | #include <net/netfilter/ipv4/nf_reject.h> | ||
14 | #include <linux/netfilter_ipv4.h> | 15 | #include <linux/netfilter_ipv4.h> |
15 | #include <net/netfilter/ipv4/nf_reject.h> | 16 | #include <net/netfilter/ipv4/nf_reject.h> |
16 | 17 | ||
diff --git a/net/ipv4/netfilter/nft_redir_ipv4.c b/net/ipv4/netfilter/nft_redir_ipv4.c new file mode 100644 index 000000000000..643c5967aa27 --- /dev/null +++ b/net/ipv4/netfilter/nft_redir_ipv4.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/netlink.h> | ||
13 | #include <linux/netfilter.h> | ||
14 | #include <linux/netfilter/nf_tables.h> | ||
15 | #include <net/netfilter/nf_tables.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/ipv4/nf_nat_redirect.h> | ||
18 | #include <net/netfilter/nft_redir.h> | ||
19 | |||
20 | static void nft_redir_ipv4_eval(const struct nft_expr *expr, | ||
21 | struct nft_data data[NFT_REG_MAX + 1], | ||
22 | const struct nft_pktinfo *pkt) | ||
23 | { | ||
24 | struct nft_redir *priv = nft_expr_priv(expr); | ||
25 | struct nf_nat_ipv4_multi_range_compat mr; | ||
26 | unsigned int verdict; | ||
27 | |||
28 | memset(&mr, 0, sizeof(mr)); | ||
29 | if (priv->sreg_proto_min) { | ||
30 | mr.range[0].min.all = (__force __be16) | ||
31 | data[priv->sreg_proto_min].data[0]; | ||
32 | mr.range[0].max.all = (__force __be16) | ||
33 | data[priv->sreg_proto_max].data[0]; | ||
34 | mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | ||
35 | } | ||
36 | |||
37 | mr.range[0].flags |= priv->flags; | ||
38 | |||
39 | verdict = nf_nat_redirect_ipv4(pkt->skb, &mr, pkt->ops->hooknum); | ||
40 | data[NFT_REG_VERDICT].verdict = verdict; | ||
41 | } | ||
42 | |||
43 | static struct nft_expr_type nft_redir_ipv4_type; | ||
44 | static const struct nft_expr_ops nft_redir_ipv4_ops = { | ||
45 | .type = &nft_redir_ipv4_type, | ||
46 | .size = NFT_EXPR_SIZE(sizeof(struct nft_redir)), | ||
47 | .eval = nft_redir_ipv4_eval, | ||
48 | .init = nft_redir_init, | ||
49 | .dump = nft_redir_dump, | ||
50 | .validate = nft_redir_validate, | ||
51 | }; | ||
52 | |||
53 | static struct nft_expr_type nft_redir_ipv4_type __read_mostly = { | ||
54 | .family = NFPROTO_IPV4, | ||
55 | .name = "redir", | ||
56 | .ops = &nft_redir_ipv4_ops, | ||
57 | .policy = nft_redir_policy, | ||
58 | .maxattr = NFTA_REDIR_MAX, | ||
59 | .owner = THIS_MODULE, | ||
60 | }; | ||
61 | |||
62 | static int __init nft_redir_ipv4_module_init(void) | ||
63 | { | ||
64 | return nft_register_expr(&nft_redir_ipv4_type); | ||
65 | } | ||
66 | |||
67 | static void __exit nft_redir_ipv4_module_exit(void) | ||
68 | { | ||
69 | nft_unregister_expr(&nft_redir_ipv4_type); | ||
70 | } | ||
71 | |||
72 | module_init(nft_redir_ipv4_module_init); | ||
73 | module_exit(nft_redir_ipv4_module_exit); | ||
74 | |||
75 | MODULE_LICENSE("GPL"); | ||
76 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | ||
77 | MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "redir"); | ||
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c index ed33299c56d1..d729542bd1b7 100644 --- a/net/ipv4/netfilter/nft_reject_ipv4.c +++ b/net/ipv4/netfilter/nft_reject_ipv4.c | |||
@@ -19,9 +19,9 @@ | |||
19 | #include <net/netfilter/ipv4/nf_reject.h> | 19 | #include <net/netfilter/ipv4/nf_reject.h> |
20 | #include <net/netfilter/nft_reject.h> | 20 | #include <net/netfilter/nft_reject.h> |
21 | 21 | ||
22 | void nft_reject_ipv4_eval(const struct nft_expr *expr, | 22 | static void nft_reject_ipv4_eval(const struct nft_expr *expr, |
23 | struct nft_data data[NFT_REG_MAX + 1], | 23 | struct nft_data data[NFT_REG_MAX + 1], |
24 | const struct nft_pktinfo *pkt) | 24 | const struct nft_pktinfo *pkt) |
25 | { | 25 | { |
26 | struct nft_reject *priv = nft_expr_priv(expr); | 26 | struct nft_reject *priv = nft_expr_priv(expr); |
27 | 27 | ||
@@ -36,7 +36,6 @@ void nft_reject_ipv4_eval(const struct nft_expr *expr, | |||
36 | 36 | ||
37 | data[NFT_REG_VERDICT].verdict = NF_DROP; | 37 | data[NFT_REG_VERDICT].verdict = NF_DROP; |
38 | } | 38 | } |
39 | EXPORT_SYMBOL_GPL(nft_reject_ipv4_eval); | ||
40 | 39 | ||
41 | static struct nft_expr_type nft_reject_ipv4_type; | 40 | static struct nft_expr_type nft_reject_ipv4_type; |
42 | static const struct nft_expr_ops nft_reject_ipv4_ops = { | 41 | static const struct nft_expr_ops nft_reject_ipv4_ops = { |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 6af874fc187f..0dbe5c7953e5 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -82,6 +82,12 @@ config NF_NAT_MASQUERADE_IPV6 | |||
82 | This is the kernel functionality to provide NAT in the masquerade | 82 | This is the kernel functionality to provide NAT in the masquerade |
83 | flavour (automatic source address selection) for IPv6. | 83 | flavour (automatic source address selection) for IPv6. |
84 | 84 | ||
85 | config NF_NAT_REDIRECT_IPV6 | ||
86 | tristate "IPv6 redirect support" | ||
87 | help | ||
88 | This is the kernel functionality to provide NAT in the redirect | ||
89 | flavour (redirect packet to local machine) for IPv6. | ||
90 | |||
85 | config NFT_MASQ_IPV6 | 91 | config NFT_MASQ_IPV6 |
86 | tristate "IPv6 masquerade support for nf_tables" | 92 | tristate "IPv6 masquerade support for nf_tables" |
87 | depends on NF_TABLES_IPV6 | 93 | depends on NF_TABLES_IPV6 |
@@ -91,6 +97,15 @@ config NFT_MASQ_IPV6 | |||
91 | This is the expression that provides IPv4 masquerading support for | 97 | This is the expression that provides IPv4 masquerading support for |
92 | nf_tables. | 98 | nf_tables. |
93 | 99 | ||
100 | config NFT_REDIR_IPV6 | ||
101 | tristate "IPv6 redirect support for nf_tables" | ||
102 | depends on NF_TABLES_IPV6 | ||
103 | depends on NFT_REDIR | ||
104 | select NF_NAT_REDIRECT_IPV6 | ||
105 | help | ||
106 | This is the expression that provides IPv4 redirect support for | ||
107 | nf_tables. | ||
108 | |||
94 | endif # NF_NAT_IPV6 | 109 | endif # NF_NAT_IPV6 |
95 | 110 | ||
96 | config IP6_NF_IPTABLES | 111 | config IP6_NF_IPTABLES |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index fbb25f01143c..d2ac9f5f212c 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | |||
19 | nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o | 19 | nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o |
20 | obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o | 20 | obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o |
21 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o | 21 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o |
22 | obj-$(CONFIG_NF_NAT_REDIRECT_IPV6) += nf_nat_redirect_ipv6.o | ||
22 | 23 | ||
23 | # defrag | 24 | # defrag |
24 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | 25 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o |
@@ -36,6 +37,7 @@ obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o | |||
36 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o | 37 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o |
37 | obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o | 38 | obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o |
38 | obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o | 39 | obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o |
40 | obj-$(CONFIG_NFT_REDIR_IPV6) += nft_redir_ipv6.o | ||
39 | 41 | ||
40 | # matches | 42 | # matches |
41 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 43 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/nf_log_ipv6.c b/net/ipv6/netfilter/nf_log_ipv6.c index 7b17a0be93e7..7fc34d1681a1 100644 --- a/net/ipv6/netfilter/nf_log_ipv6.c +++ b/net/ipv6/netfilter/nf_log_ipv6.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
8 | 9 | ||
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
10 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
@@ -398,8 +399,17 @@ static int __init nf_log_ipv6_init(void) | |||
398 | if (ret < 0) | 399 | if (ret < 0) |
399 | return ret; | 400 | return ret; |
400 | 401 | ||
401 | nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); | 402 | ret = nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); |
403 | if (ret < 0) { | ||
404 | pr_err("failed to register logger\n"); | ||
405 | goto err1; | ||
406 | } | ||
407 | |||
402 | return 0; | 408 | return 0; |
409 | |||
410 | err1: | ||
411 | unregister_pernet_subsys(&nf_log_ipv6_net_ops); | ||
412 | return ret; | ||
403 | } | 413 | } |
404 | 414 | ||
405 | static void __exit nf_log_ipv6_exit(void) | 415 | static void __exit nf_log_ipv6_exit(void) |
diff --git a/net/ipv6/netfilter/nf_nat_redirect_ipv6.c b/net/ipv6/netfilter/nf_nat_redirect_ipv6.c new file mode 100644 index 000000000000..ea1308aeb048 --- /dev/null +++ b/net/ipv6/netfilter/nf_nat_redirect_ipv6.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * (C) 1999-2001 Paul `Rusty' Russell | ||
3 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> | ||
4 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
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 | * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 | ||
11 | * NAT funded by Astaro. | ||
12 | */ | ||
13 | |||
14 | #include <linux/if.h> | ||
15 | #include <linux/inetdevice.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/netfilter.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/netfilter_ipv6.h> | ||
23 | #include <linux/netfilter/x_tables.h> | ||
24 | #include <net/addrconf.h> | ||
25 | #include <net/checksum.h> | ||
26 | #include <net/protocol.h> | ||
27 | #include <net/netfilter/nf_nat.h> | ||
28 | #include <net/netfilter/ipv6/nf_nat_redirect.h> | ||
29 | |||
30 | static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; | ||
31 | |||
32 | unsigned int | ||
33 | nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, | ||
34 | unsigned int hooknum) | ||
35 | { | ||
36 | struct nf_nat_range newrange; | ||
37 | struct in6_addr newdst; | ||
38 | enum ip_conntrack_info ctinfo; | ||
39 | struct nf_conn *ct; | ||
40 | |||
41 | ct = nf_ct_get(skb, &ctinfo); | ||
42 | if (hooknum == NF_INET_LOCAL_OUT) { | ||
43 | newdst = loopback_addr; | ||
44 | } else { | ||
45 | struct inet6_dev *idev; | ||
46 | struct inet6_ifaddr *ifa; | ||
47 | bool addr = false; | ||
48 | |||
49 | rcu_read_lock(); | ||
50 | idev = __in6_dev_get(skb->dev); | ||
51 | if (idev != NULL) { | ||
52 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
53 | newdst = ifa->addr; | ||
54 | addr = true; | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | rcu_read_unlock(); | ||
59 | |||
60 | if (!addr) | ||
61 | return NF_DROP; | ||
62 | } | ||
63 | |||
64 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
65 | newrange.min_addr.in6 = newdst; | ||
66 | newrange.max_addr.in6 = newdst; | ||
67 | newrange.min_proto = range->min_proto; | ||
68 | newrange.max_proto = range->max_proto; | ||
69 | |||
70 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | ||
71 | } | ||
72 | EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6); | ||
73 | |||
74 | MODULE_LICENSE("GPL"); | ||
75 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 015eb8a80766..d05b36440e8b 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <net/ip6_route.h> | 11 | #include <net/ip6_route.h> |
12 | #include <net/ip6_fib.h> | 12 | #include <net/ip6_fib.h> |
13 | #include <net/ip6_checksum.h> | 13 | #include <net/ip6_checksum.h> |
14 | #include <net/netfilter/ipv6/nf_reject.h> | ||
14 | #include <linux/netfilter_ipv6.h> | 15 | #include <linux/netfilter_ipv6.h> |
15 | #include <net/netfilter/ipv6/nf_reject.h> | 16 | #include <net/netfilter/ipv6/nf_reject.h> |
16 | 17 | ||
diff --git a/net/ipv6/netfilter/nft_redir_ipv6.c b/net/ipv6/netfilter/nft_redir_ipv6.c new file mode 100644 index 000000000000..83420eeaad1c --- /dev/null +++ b/net/ipv6/netfilter/nft_redir_ipv6.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/netlink.h> | ||
13 | #include <linux/netfilter.h> | ||
14 | #include <linux/netfilter/nf_tables.h> | ||
15 | #include <net/netfilter/nf_tables.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nft_redir.h> | ||
18 | #include <net/netfilter/ipv6/nf_nat_redirect.h> | ||
19 | |||
20 | static void nft_redir_ipv6_eval(const struct nft_expr *expr, | ||
21 | struct nft_data data[NFT_REG_MAX + 1], | ||
22 | const struct nft_pktinfo *pkt) | ||
23 | { | ||
24 | struct nft_redir *priv = nft_expr_priv(expr); | ||
25 | struct nf_nat_range range; | ||
26 | unsigned int verdict; | ||
27 | |||
28 | memset(&range, 0, sizeof(range)); | ||
29 | if (priv->sreg_proto_min) { | ||
30 | range.min_proto.all = (__force __be16) | ||
31 | data[priv->sreg_proto_min].data[0]; | ||
32 | range.max_proto.all = (__force __be16) | ||
33 | data[priv->sreg_proto_max].data[0]; | ||
34 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | ||
35 | } | ||
36 | |||
37 | range.flags |= priv->flags; | ||
38 | |||
39 | verdict = nf_nat_redirect_ipv6(pkt->skb, &range, pkt->ops->hooknum); | ||
40 | data[NFT_REG_VERDICT].verdict = verdict; | ||
41 | } | ||
42 | |||
43 | static struct nft_expr_type nft_redir_ipv6_type; | ||
44 | static const struct nft_expr_ops nft_redir_ipv6_ops = { | ||
45 | .type = &nft_redir_ipv6_type, | ||
46 | .size = NFT_EXPR_SIZE(sizeof(struct nft_redir)), | ||
47 | .eval = nft_redir_ipv6_eval, | ||
48 | .init = nft_redir_init, | ||
49 | .dump = nft_redir_dump, | ||
50 | .validate = nft_redir_validate, | ||
51 | }; | ||
52 | |||
53 | static struct nft_expr_type nft_redir_ipv6_type __read_mostly = { | ||
54 | .family = NFPROTO_IPV6, | ||
55 | .name = "redir", | ||
56 | .ops = &nft_redir_ipv6_ops, | ||
57 | .policy = nft_redir_policy, | ||
58 | .maxattr = NFTA_REDIR_MAX, | ||
59 | .owner = THIS_MODULE, | ||
60 | }; | ||
61 | |||
62 | static int __init nft_redir_ipv6_module_init(void) | ||
63 | { | ||
64 | return nft_register_expr(&nft_redir_ipv6_type); | ||
65 | } | ||
66 | |||
67 | static void __exit nft_redir_ipv6_module_exit(void) | ||
68 | { | ||
69 | nft_unregister_expr(&nft_redir_ipv6_type); | ||
70 | } | ||
71 | |||
72 | module_init(nft_redir_ipv6_module_init); | ||
73 | module_exit(nft_redir_ipv6_module_exit); | ||
74 | |||
75 | MODULE_LICENSE("GPL"); | ||
76 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | ||
77 | MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "redir"); | ||
diff --git a/net/ipv6/netfilter/nft_reject_ipv6.c b/net/ipv6/netfilter/nft_reject_ipv6.c index 0bc19fa87821..f73285924144 100644 --- a/net/ipv6/netfilter/nft_reject_ipv6.c +++ b/net/ipv6/netfilter/nft_reject_ipv6.c | |||
@@ -19,9 +19,9 @@ | |||
19 | #include <net/netfilter/nft_reject.h> | 19 | #include <net/netfilter/nft_reject.h> |
20 | #include <net/netfilter/ipv6/nf_reject.h> | 20 | #include <net/netfilter/ipv6/nf_reject.h> |
21 | 21 | ||
22 | void nft_reject_ipv6_eval(const struct nft_expr *expr, | 22 | static void nft_reject_ipv6_eval(const struct nft_expr *expr, |
23 | struct nft_data data[NFT_REG_MAX + 1], | 23 | struct nft_data data[NFT_REG_MAX + 1], |
24 | const struct nft_pktinfo *pkt) | 24 | const struct nft_pktinfo *pkt) |
25 | { | 25 | { |
26 | struct nft_reject *priv = nft_expr_priv(expr); | 26 | struct nft_reject *priv = nft_expr_priv(expr); |
27 | struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); | 27 | struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); |
@@ -38,7 +38,6 @@ void nft_reject_ipv6_eval(const struct nft_expr *expr, | |||
38 | 38 | ||
39 | data[NFT_REG_VERDICT].verdict = NF_DROP; | 39 | data[NFT_REG_VERDICT].verdict = NF_DROP; |
40 | } | 40 | } |
41 | EXPORT_SYMBOL_GPL(nft_reject_ipv6_eval); | ||
42 | 41 | ||
43 | static struct nft_expr_type nft_reject_ipv6_type; | 42 | static struct nft_expr_type nft_reject_ipv6_type; |
44 | static const struct nft_expr_ops nft_reject_ipv6_ops = { | 43 | static const struct nft_expr_ops nft_reject_ipv6_ops = { |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index ae5096ab65eb..57f15a9aa481 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -505,6 +505,15 @@ config NFT_MASQ | |||
505 | This option adds the "masquerade" expression that you can use | 505 | This option adds the "masquerade" expression that you can use |
506 | to perform NAT in the masquerade flavour. | 506 | to perform NAT in the masquerade flavour. |
507 | 507 | ||
508 | config NFT_REDIR | ||
509 | depends on NF_TABLES | ||
510 | depends on NF_CONNTRACK | ||
511 | depends on NF_NAT | ||
512 | tristate "Netfilter nf_tables redirect support" | ||
513 | help | ||
514 | This options adds the "redirect" expression that you can use | ||
515 | to perform NAT in the redirect flavour. | ||
516 | |||
508 | config NFT_NAT | 517 | config NFT_NAT |
509 | depends on NF_TABLES | 518 | depends on NF_TABLES |
510 | depends on NF_CONNTRACK | 519 | depends on NF_CONNTRACK |
@@ -835,6 +844,8 @@ config NETFILTER_XT_TARGET_RATEEST | |||
835 | config NETFILTER_XT_TARGET_REDIRECT | 844 | config NETFILTER_XT_TARGET_REDIRECT |
836 | tristate "REDIRECT target support" | 845 | tristate "REDIRECT target support" |
837 | depends on NF_NAT | 846 | depends on NF_NAT |
847 | select NF_NAT_REDIRECT_IPV4 if NF_NAT_IPV4 | ||
848 | select NF_NAT_REDIRECT_IPV6 if NF_NAT_IPV6 | ||
838 | ---help--- | 849 | ---help--- |
839 | REDIRECT is a special case of NAT: all incoming connections are | 850 | REDIRECT is a special case of NAT: all incoming connections are |
840 | mapped onto the incoming interface's address, causing the packets to | 851 | mapped onto the incoming interface's address, causing the packets to |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a9571be3f791..f3eb4680f2ec 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -88,6 +88,7 @@ obj-$(CONFIG_NFT_HASH) += nft_hash.o | |||
88 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o | 88 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o |
89 | obj-$(CONFIG_NFT_LOG) += nft_log.o | 89 | obj-$(CONFIG_NFT_LOG) += nft_log.o |
90 | obj-$(CONFIG_NFT_MASQ) += nft_masq.o | 90 | obj-$(CONFIG_NFT_MASQ) += nft_masq.o |
91 | obj-$(CONFIG_NFT_REDIR) += nft_redir.o | ||
91 | 92 | ||
92 | # generic X tables | 93 | # generic X tables |
93 | obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o | 94 | obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 024a2e25c8a4..fea9ef566427 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/if.h> | 18 | #include <linux/if.h> |
19 | #include <linux/netdevice.h> | 19 | #include <linux/netdevice.h> |
20 | #include <linux/netfilter_ipv6.h> | ||
20 | #include <linux/inetdevice.h> | 21 | #include <linux/inetdevice.h> |
21 | #include <linux/proc_fs.h> | 22 | #include <linux/proc_fs.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index ac7ba689efe7..b8295a430a56 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -465,8 +465,7 @@ __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc) | |||
465 | 465 | ||
466 | static void ip_vs_service_free(struct ip_vs_service *svc) | 466 | static void ip_vs_service_free(struct ip_vs_service *svc) |
467 | { | 467 | { |
468 | if (svc->stats.cpustats) | 468 | free_percpu(svc->stats.cpustats); |
469 | free_percpu(svc->stats.cpustats); | ||
470 | kfree(svc); | 469 | kfree(svc); |
471 | } | 470 | } |
472 | 471 | ||
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c index 1a82b29ce8ea..0df17caa8af6 100644 --- a/net/netfilter/ipvs/ip_vs_pe.c +++ b/net/netfilter/ipvs/ip_vs_pe.c | |||
@@ -37,8 +37,7 @@ struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name) | |||
37 | rcu_read_unlock(); | 37 | rcu_read_unlock(); |
38 | return pe; | 38 | return pe; |
39 | } | 39 | } |
40 | if (pe->module) | 40 | module_put(pe->module); |
41 | module_put(pe->module); | ||
42 | } | 41 | } |
43 | rcu_read_unlock(); | 42 | rcu_read_unlock(); |
44 | 43 | ||
diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c index 4dbcda6258bc..199760c71f39 100644 --- a/net/netfilter/ipvs/ip_vs_sched.c +++ b/net/netfilter/ipvs/ip_vs_sched.c | |||
@@ -104,8 +104,7 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name) | |||
104 | mutex_unlock(&ip_vs_sched_mutex); | 104 | mutex_unlock(&ip_vs_sched_mutex); |
105 | return sched; | 105 | return sched; |
106 | } | 106 | } |
107 | if (sched->module) | 107 | module_put(sched->module); |
108 | module_put(sched->module); | ||
109 | } | 108 | } |
110 | 109 | ||
111 | mutex_unlock(&ip_vs_sched_mutex); | 110 | mutex_unlock(&ip_vs_sched_mutex); |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 7162c86fd50d..c47ffd7a0a70 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
@@ -820,8 +820,7 @@ ip_vs_conn_fill_param_sync(struct net *net, int af, union ip_vs_sync_conn *sc, | |||
820 | 820 | ||
821 | p->pe_data = kmemdup(pe_data, pe_data_len, GFP_ATOMIC); | 821 | p->pe_data = kmemdup(pe_data, pe_data_len, GFP_ATOMIC); |
822 | if (!p->pe_data) { | 822 | if (!p->pe_data) { |
823 | if (p->pe->module) | 823 | module_put(p->pe->module); |
824 | module_put(p->pe->module); | ||
825 | return -ENOMEM; | 824 | return -ENOMEM; |
826 | } | 825 | } |
827 | p->pe_data_len = pe_data_len; | 826 | p->pe_data_len = pe_data_len; |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index bd90bf8107da..1f933136155a 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -293,7 +293,6 @@ __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, | |||
293 | &dest->addr.ip, &dest_dst->dst_saddr.ip, | 293 | &dest->addr.ip, &dest_dst->dst_saddr.ip, |
294 | atomic_read(&rt->dst.__refcnt)); | 294 | atomic_read(&rt->dst.__refcnt)); |
295 | } | 295 | } |
296 | daddr = dest->addr.ip; | ||
297 | if (ret_saddr) | 296 | if (ret_saddr) |
298 | *ret_saddr = dest_dst->dst_saddr.ip; | 297 | *ret_saddr = dest_dst->dst_saddr.ip; |
299 | } else { | 298 | } else { |
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 3a3a60b126e0..1d69f5b9748f 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c | |||
@@ -728,7 +728,8 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, | |||
728 | 728 | ||
729 | /* If the calling party is on the same side of the forward-to party, | 729 | /* If the calling party is on the same side of the forward-to party, |
730 | * we don't need to track the second call */ | 730 | * we don't need to track the second call */ |
731 | static int callforward_do_filter(const union nf_inet_addr *src, | 731 | static int callforward_do_filter(struct net *net, |
732 | const union nf_inet_addr *src, | ||
732 | const union nf_inet_addr *dst, | 733 | const union nf_inet_addr *dst, |
733 | u_int8_t family) | 734 | u_int8_t family) |
734 | { | 735 | { |
@@ -750,9 +751,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, | |||
750 | 751 | ||
751 | memset(&fl2, 0, sizeof(fl2)); | 752 | memset(&fl2, 0, sizeof(fl2)); |
752 | fl2.daddr = dst->ip; | 753 | fl2.daddr = dst->ip; |
753 | if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, | 754 | if (!afinfo->route(net, (struct dst_entry **)&rt1, |
754 | flowi4_to_flowi(&fl1), false)) { | 755 | flowi4_to_flowi(&fl1), false)) { |
755 | if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, | 756 | if (!afinfo->route(net, (struct dst_entry **)&rt2, |
756 | flowi4_to_flowi(&fl2), false)) { | 757 | flowi4_to_flowi(&fl2), false)) { |
757 | if (rt_nexthop(rt1, fl1.daddr) == | 758 | if (rt_nexthop(rt1, fl1.daddr) == |
758 | rt_nexthop(rt2, fl2.daddr) && | 759 | rt_nexthop(rt2, fl2.daddr) && |
@@ -774,9 +775,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, | |||
774 | 775 | ||
775 | memset(&fl2, 0, sizeof(fl2)); | 776 | memset(&fl2, 0, sizeof(fl2)); |
776 | fl2.daddr = dst->in6; | 777 | fl2.daddr = dst->in6; |
777 | if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, | 778 | if (!afinfo->route(net, (struct dst_entry **)&rt1, |
778 | flowi6_to_flowi(&fl1), false)) { | 779 | flowi6_to_flowi(&fl1), false)) { |
779 | if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, | 780 | if (!afinfo->route(net, (struct dst_entry **)&rt2, |
780 | flowi6_to_flowi(&fl2), false)) { | 781 | flowi6_to_flowi(&fl2), false)) { |
781 | if (ipv6_addr_equal(rt6_nexthop(rt1), | 782 | if (ipv6_addr_equal(rt6_nexthop(rt1), |
782 | rt6_nexthop(rt2)) && | 783 | rt6_nexthop(rt2)) && |
@@ -807,6 +808,7 @@ static int expect_callforwarding(struct sk_buff *skb, | |||
807 | __be16 port; | 808 | __be16 port; |
808 | union nf_inet_addr addr; | 809 | union nf_inet_addr addr; |
809 | struct nf_conntrack_expect *exp; | 810 | struct nf_conntrack_expect *exp; |
811 | struct net *net = nf_ct_net(ct); | ||
810 | typeof(nat_callforwarding_hook) nat_callforwarding; | 812 | typeof(nat_callforwarding_hook) nat_callforwarding; |
811 | 813 | ||
812 | /* Read alternativeAddress */ | 814 | /* Read alternativeAddress */ |
@@ -816,7 +818,7 @@ static int expect_callforwarding(struct sk_buff *skb, | |||
816 | /* If the calling party is on the same side of the forward-to party, | 818 | /* If the calling party is on the same side of the forward-to party, |
817 | * we don't need to track the second call */ | 819 | * we don't need to track the second call */ |
818 | if (callforward_filter && | 820 | if (callforward_filter && |
819 | callforward_do_filter(&addr, &ct->tuplehash[!dir].tuple.src.u3, | 821 | callforward_do_filter(net, &addr, &ct->tuplehash[!dir].tuple.src.u3, |
820 | nf_ct_l3num(ct))) { | 822 | nf_ct_l3num(ct))) { |
821 | pr_debug("nf_ct_q931: Call Forwarding not tracked\n"); | 823 | pr_debug("nf_ct_q931: Call Forwarding not tracked\n"); |
822 | return 0; | 824 | return 0; |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 5b3eae7d4c9a..bd9d31537905 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -250,7 +250,7 @@ out: | |||
250 | } | 250 | } |
251 | EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper); | 251 | EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper); |
252 | 252 | ||
253 | /* appropiate ct lock protecting must be taken by caller */ | 253 | /* appropriate ct lock protecting must be taken by caller */ |
254 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | 254 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, |
255 | const struct nf_conntrack_helper *me) | 255 | const struct nf_conntrack_helper *me) |
256 | { | 256 | { |
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index d7197649dba6..49a64174f3f1 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c | |||
@@ -19,6 +19,9 @@ | |||
19 | static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; | 19 | static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; |
20 | static DEFINE_MUTEX(nf_log_mutex); | 20 | static DEFINE_MUTEX(nf_log_mutex); |
21 | 21 | ||
22 | #define nft_log_dereference(logger) \ | ||
23 | rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex)) | ||
24 | |||
22 | static struct nf_logger *__find_logger(int pf, const char *str_logger) | 25 | static struct nf_logger *__find_logger(int pf, const char *str_logger) |
23 | { | 26 | { |
24 | struct nf_logger *log; | 27 | struct nf_logger *log; |
@@ -28,8 +31,7 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger) | |||
28 | if (loggers[pf][i] == NULL) | 31 | if (loggers[pf][i] == NULL) |
29 | continue; | 32 | continue; |
30 | 33 | ||
31 | log = rcu_dereference_protected(loggers[pf][i], | 34 | log = nft_log_dereference(loggers[pf][i]); |
32 | lockdep_is_held(&nf_log_mutex)); | ||
33 | if (!strncasecmp(str_logger, log->name, strlen(log->name))) | 35 | if (!strncasecmp(str_logger, log->name, strlen(log->name))) |
34 | return log; | 36 | return log; |
35 | } | 37 | } |
@@ -45,8 +47,7 @@ void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger) | |||
45 | return; | 47 | return; |
46 | 48 | ||
47 | mutex_lock(&nf_log_mutex); | 49 | mutex_lock(&nf_log_mutex); |
48 | log = rcu_dereference_protected(net->nf.nf_loggers[pf], | 50 | log = nft_log_dereference(net->nf.nf_loggers[pf]); |
49 | lockdep_is_held(&nf_log_mutex)); | ||
50 | if (log == NULL) | 51 | if (log == NULL) |
51 | rcu_assign_pointer(net->nf.nf_loggers[pf], logger); | 52 | rcu_assign_pointer(net->nf.nf_loggers[pf], logger); |
52 | 53 | ||
@@ -61,8 +62,7 @@ void nf_log_unset(struct net *net, const struct nf_logger *logger) | |||
61 | 62 | ||
62 | mutex_lock(&nf_log_mutex); | 63 | mutex_lock(&nf_log_mutex); |
63 | for (i = 0; i < NFPROTO_NUMPROTO; i++) { | 64 | for (i = 0; i < NFPROTO_NUMPROTO; i++) { |
64 | log = rcu_dereference_protected(net->nf.nf_loggers[i], | 65 | log = nft_log_dereference(net->nf.nf_loggers[i]); |
65 | lockdep_is_held(&nf_log_mutex)); | ||
66 | if (log == logger) | 66 | if (log == logger) |
67 | RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL); | 67 | RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL); |
68 | } | 68 | } |
@@ -75,6 +75,7 @@ EXPORT_SYMBOL(nf_log_unset); | |||
75 | int nf_log_register(u_int8_t pf, struct nf_logger *logger) | 75 | int nf_log_register(u_int8_t pf, struct nf_logger *logger) |
76 | { | 76 | { |
77 | int i; | 77 | int i; |
78 | int ret = 0; | ||
78 | 79 | ||
79 | if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) | 80 | if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) |
80 | return -EINVAL; | 81 | return -EINVAL; |
@@ -82,16 +83,25 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger) | |||
82 | mutex_lock(&nf_log_mutex); | 83 | mutex_lock(&nf_log_mutex); |
83 | 84 | ||
84 | if (pf == NFPROTO_UNSPEC) { | 85 | if (pf == NFPROTO_UNSPEC) { |
86 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { | ||
87 | if (rcu_access_pointer(loggers[i][logger->type])) { | ||
88 | ret = -EEXIST; | ||
89 | goto unlock; | ||
90 | } | ||
91 | } | ||
85 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | 92 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) |
86 | rcu_assign_pointer(loggers[i][logger->type], logger); | 93 | rcu_assign_pointer(loggers[i][logger->type], logger); |
87 | } else { | 94 | } else { |
88 | /* register at end of list to honor first register win */ | 95 | if (rcu_access_pointer(loggers[pf][logger->type])) { |
96 | ret = -EEXIST; | ||
97 | goto unlock; | ||
98 | } | ||
89 | rcu_assign_pointer(loggers[pf][logger->type], logger); | 99 | rcu_assign_pointer(loggers[pf][logger->type], logger); |
90 | } | 100 | } |
91 | 101 | ||
102 | unlock: | ||
92 | mutex_unlock(&nf_log_mutex); | 103 | mutex_unlock(&nf_log_mutex); |
93 | 104 | return ret; | |
94 | return 0; | ||
95 | } | 105 | } |
96 | EXPORT_SYMBOL(nf_log_register); | 106 | EXPORT_SYMBOL(nf_log_register); |
97 | 107 | ||
@@ -144,8 +154,7 @@ int nf_logger_find_get(int pf, enum nf_log_type type) | |||
144 | struct nf_logger *logger; | 154 | struct nf_logger *logger; |
145 | int ret = -ENOENT; | 155 | int ret = -ENOENT; |
146 | 156 | ||
147 | logger = loggers[pf][type]; | 157 | if (rcu_access_pointer(loggers[pf][type]) == NULL) |
148 | if (logger == NULL) | ||
149 | request_module("nf-logger-%u-%u", pf, type); | 158 | request_module("nf-logger-%u-%u", pf, type); |
150 | 159 | ||
151 | rcu_read_lock(); | 160 | rcu_read_lock(); |
@@ -297,8 +306,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
297 | int i, ret; | 306 | int i, ret; |
298 | struct net *net = seq_file_net(s); | 307 | struct net *net = seq_file_net(s); |
299 | 308 | ||
300 | logger = rcu_dereference_protected(net->nf.nf_loggers[*pos], | 309 | logger = nft_log_dereference(net->nf.nf_loggers[*pos]); |
301 | lockdep_is_held(&nf_log_mutex)); | ||
302 | 310 | ||
303 | if (!logger) | 311 | if (!logger) |
304 | ret = seq_printf(s, "%2lld NONE (", *pos); | 312 | ret = seq_printf(s, "%2lld NONE (", *pos); |
@@ -312,8 +320,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
312 | if (loggers[*pos][i] == NULL) | 320 | if (loggers[*pos][i] == NULL) |
313 | continue; | 321 | continue; |
314 | 322 | ||
315 | logger = rcu_dereference_protected(loggers[*pos][i], | 323 | logger = nft_log_dereference(loggers[*pos][i]); |
316 | lockdep_is_held(&nf_log_mutex)); | ||
317 | ret = seq_printf(s, "%s", logger->name); | 324 | ret = seq_printf(s, "%s", logger->name); |
318 | if (ret < 0) | 325 | if (ret < 0) |
319 | return ret; | 326 | return ret; |
@@ -385,8 +392,7 @@ static int nf_log_proc_dostring(struct ctl_table *table, int write, | |||
385 | mutex_unlock(&nf_log_mutex); | 392 | mutex_unlock(&nf_log_mutex); |
386 | } else { | 393 | } else { |
387 | mutex_lock(&nf_log_mutex); | 394 | mutex_lock(&nf_log_mutex); |
388 | logger = rcu_dereference_protected(net->nf.nf_loggers[tindex], | 395 | logger = nft_log_dereference(net->nf.nf_loggers[tindex]); |
389 | lockdep_is_held(&nf_log_mutex)); | ||
390 | if (!logger) | 396 | if (!logger) |
391 | table->data = "NONE"; | 397 | table->data = "NONE"; |
392 | else | 398 | else |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 66e8425dbfe7..129a8daa4abf 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -2477,7 +2477,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, | |||
2477 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 2477 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
2478 | int err; | 2478 | int err; |
2479 | 2479 | ||
2480 | /* Verify existance before starting dump */ | 2480 | /* Verify existence before starting dump */ |
2481 | err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla); | 2481 | err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla); |
2482 | if (err < 0) | 2482 | if (err < 0) |
2483 | return err; | 2483 | return err; |
@@ -3665,8 +3665,7 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3665 | break; | 3665 | break; |
3666 | case NFT_MSG_NEWCHAIN: | 3666 | case NFT_MSG_NEWCHAIN: |
3667 | if (nft_trans_chain_update(trans)) { | 3667 | if (nft_trans_chain_update(trans)) { |
3668 | if (nft_trans_chain_stats(trans)) | 3668 | free_percpu(nft_trans_chain_stats(trans)); |
3669 | free_percpu(nft_trans_chain_stats(trans)); | ||
3670 | 3669 | ||
3671 | nft_trans_destroy(trans); | 3670 | nft_trans_destroy(trans); |
3672 | } else { | 3671 | } else { |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 5f1be5ba3559..11d85b3813f2 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -12,6 +12,9 @@ | |||
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | |||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | |||
15 | #include <linux/module.h> | 18 | #include <linux/module.h> |
16 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
17 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
@@ -337,9 +340,6 @@ nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size, | |||
337 | 340 | ||
338 | skb = nfnetlink_alloc_skb(net, pkt_size, | 341 | skb = nfnetlink_alloc_skb(net, pkt_size, |
339 | peer_portid, GFP_ATOMIC); | 342 | peer_portid, GFP_ATOMIC); |
340 | if (!skb) | ||
341 | pr_err("nfnetlink_log: can't even alloc %u bytes\n", | ||
342 | pkt_size); | ||
343 | } | 343 | } |
344 | } | 344 | } |
345 | 345 | ||
@@ -570,10 +570,8 @@ __build_packet_message(struct nfnl_log_net *log, | |||
570 | struct nlattr *nla; | 570 | struct nlattr *nla; |
571 | int size = nla_attr_size(data_len); | 571 | int size = nla_attr_size(data_len); |
572 | 572 | ||
573 | if (skb_tailroom(inst->skb) < nla_total_size(data_len)) { | 573 | if (skb_tailroom(inst->skb) < nla_total_size(data_len)) |
574 | printk(KERN_WARNING "nfnetlink_log: no tailroom!\n"); | 574 | goto nla_put_failure; |
575 | return -1; | ||
576 | } | ||
577 | 575 | ||
578 | nla = (struct nlattr *)skb_put(inst->skb, nla_total_size(data_len)); | 576 | nla = (struct nlattr *)skb_put(inst->skb, nla_total_size(data_len)); |
579 | nla->nla_type = NFULA_PAYLOAD; | 577 | nla->nla_type = NFULA_PAYLOAD; |
@@ -1069,19 +1067,19 @@ static int __init nfnetlink_log_init(void) | |||
1069 | netlink_register_notifier(&nfulnl_rtnl_notifier); | 1067 | netlink_register_notifier(&nfulnl_rtnl_notifier); |
1070 | status = nfnetlink_subsys_register(&nfulnl_subsys); | 1068 | status = nfnetlink_subsys_register(&nfulnl_subsys); |
1071 | if (status < 0) { | 1069 | if (status < 0) { |
1072 | pr_err("log: failed to create netlink socket\n"); | 1070 | pr_err("failed to create netlink socket\n"); |
1073 | goto cleanup_netlink_notifier; | 1071 | goto cleanup_netlink_notifier; |
1074 | } | 1072 | } |
1075 | 1073 | ||
1076 | status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); | 1074 | status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); |
1077 | if (status < 0) { | 1075 | if (status < 0) { |
1078 | pr_err("log: failed to register logger\n"); | 1076 | pr_err("failed to register logger\n"); |
1079 | goto cleanup_subsys; | 1077 | goto cleanup_subsys; |
1080 | } | 1078 | } |
1081 | 1079 | ||
1082 | status = register_pernet_subsys(&nfnl_log_net_ops); | 1080 | status = register_pernet_subsys(&nfnl_log_net_ops); |
1083 | if (status < 0) { | 1081 | if (status < 0) { |
1084 | pr_err("log: failed to register pernet ops\n"); | 1082 | pr_err("failed to register pernet ops\n"); |
1085 | goto cleanup_logger; | 1083 | goto cleanup_logger; |
1086 | } | 1084 | } |
1087 | return status; | 1085 | return status; |
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 1e7c076ca63a..e99911eda915 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c | |||
@@ -165,6 +165,12 @@ void nft_meta_get_eval(const struct nft_expr *expr, | |||
165 | goto err; | 165 | goto err; |
166 | dest->data[0] = out->group; | 166 | dest->data[0] = out->group; |
167 | break; | 167 | break; |
168 | case NFT_META_CGROUP: | ||
169 | if (skb->sk == NULL) | ||
170 | break; | ||
171 | |||
172 | dest->data[0] = skb->sk->sk_classid; | ||
173 | break; | ||
168 | default: | 174 | default: |
169 | WARN_ON(1); | 175 | WARN_ON(1); |
170 | goto err; | 176 | goto err; |
@@ -240,6 +246,7 @@ int nft_meta_get_init(const struct nft_ctx *ctx, | |||
240 | case NFT_META_CPU: | 246 | case NFT_META_CPU: |
241 | case NFT_META_IIFGROUP: | 247 | case NFT_META_IIFGROUP: |
242 | case NFT_META_OIFGROUP: | 248 | case NFT_META_OIFGROUP: |
249 | case NFT_META_CGROUP: | ||
243 | break; | 250 | break; |
244 | default: | 251 | default: |
245 | return -EOPNOTSUPP; | 252 | return -EOPNOTSUPP; |
diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c new file mode 100644 index 000000000000..9e8093f28311 --- /dev/null +++ b/net/netfilter/nft_redir.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/netlink.h> | ||
13 | #include <linux/netfilter.h> | ||
14 | #include <linux/netfilter/nf_tables.h> | ||
15 | #include <net/netfilter/nf_nat.h> | ||
16 | #include <net/netfilter/nf_tables.h> | ||
17 | #include <net/netfilter/nft_redir.h> | ||
18 | |||
19 | const struct nla_policy nft_redir_policy[NFTA_REDIR_MAX + 1] = { | ||
20 | [NFTA_REDIR_REG_PROTO_MIN] = { .type = NLA_U32 }, | ||
21 | [NFTA_REDIR_REG_PROTO_MAX] = { .type = NLA_U32 }, | ||
22 | [NFTA_REDIR_FLAGS] = { .type = NLA_U32 }, | ||
23 | }; | ||
24 | EXPORT_SYMBOL_GPL(nft_redir_policy); | ||
25 | |||
26 | int nft_redir_init(const struct nft_ctx *ctx, | ||
27 | const struct nft_expr *expr, | ||
28 | const struct nlattr * const tb[]) | ||
29 | { | ||
30 | struct nft_redir *priv = nft_expr_priv(expr); | ||
31 | int err; | ||
32 | |||
33 | err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
34 | if (err < 0) | ||
35 | return err; | ||
36 | |||
37 | if (tb[NFTA_REDIR_REG_PROTO_MIN]) { | ||
38 | priv->sreg_proto_min = | ||
39 | ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MIN])); | ||
40 | |||
41 | err = nft_validate_input_register(priv->sreg_proto_min); | ||
42 | if (err < 0) | ||
43 | return err; | ||
44 | |||
45 | if (tb[NFTA_REDIR_REG_PROTO_MAX]) { | ||
46 | priv->sreg_proto_max = | ||
47 | ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MAX])); | ||
48 | |||
49 | err = nft_validate_input_register(priv->sreg_proto_max); | ||
50 | if (err < 0) | ||
51 | return err; | ||
52 | } else { | ||
53 | priv->sreg_proto_max = priv->sreg_proto_min; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | if (tb[NFTA_REDIR_FLAGS]) { | ||
58 | priv->flags = ntohl(nla_get_be32(tb[NFTA_REDIR_FLAGS])); | ||
59 | if (priv->flags & ~NF_NAT_RANGE_MASK) | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(nft_redir_init); | ||
66 | |||
67 | int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
68 | { | ||
69 | const struct nft_redir *priv = nft_expr_priv(expr); | ||
70 | |||
71 | if (priv->sreg_proto_min) { | ||
72 | if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MIN, | ||
73 | htonl(priv->sreg_proto_min))) | ||
74 | goto nla_put_failure; | ||
75 | if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MAX, | ||
76 | htonl(priv->sreg_proto_max))) | ||
77 | goto nla_put_failure; | ||
78 | } | ||
79 | |||
80 | if (priv->flags != 0 && | ||
81 | nla_put_be32(skb, NFTA_REDIR_FLAGS, htonl(priv->flags))) | ||
82 | goto nla_put_failure; | ||
83 | |||
84 | return 0; | ||
85 | |||
86 | nla_put_failure: | ||
87 | return -1; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(nft_redir_dump); | ||
90 | |||
91 | int nft_redir_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
92 | const struct nft_data **data) | ||
93 | { | ||
94 | return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(nft_redir_validate); | ||
97 | |||
98 | MODULE_LICENSE("GPL"); | ||
99 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | ||
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index ae8271652efa..3f83d38c4e5b 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c | |||
@@ -37,7 +37,8 @@ dscp_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
37 | if (!skb_make_writable(skb, sizeof(struct iphdr))) | 37 | if (!skb_make_writable(skb, sizeof(struct iphdr))) |
38 | return NF_DROP; | 38 | return NF_DROP; |
39 | 39 | ||
40 | ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK), | 40 | ipv4_change_dsfield(ip_hdr(skb), |
41 | (__force __u8)(~XT_DSCP_MASK), | ||
41 | dinfo->dscp << XT_DSCP_SHIFT); | 42 | dinfo->dscp << XT_DSCP_SHIFT); |
42 | 43 | ||
43 | } | 44 | } |
@@ -54,7 +55,8 @@ dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
54 | if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) | 55 | if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) |
55 | return NF_DROP; | 56 | return NF_DROP; |
56 | 57 | ||
57 | ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK), | 58 | ipv6_change_dsfield(ipv6_hdr(skb), |
59 | (__force __u8)(~XT_DSCP_MASK), | ||
58 | dinfo->dscp << XT_DSCP_SHIFT); | 60 | dinfo->dscp << XT_DSCP_SHIFT); |
59 | } | 61 | } |
60 | return XT_CONTINUE; | 62 | return XT_CONTINUE; |
diff --git a/net/netfilter/xt_REDIRECT.c b/net/netfilter/xt_REDIRECT.c index 22a10309297c..b6ec67efd900 100644 --- a/net/netfilter/xt_REDIRECT.c +++ b/net/netfilter/xt_REDIRECT.c | |||
@@ -26,48 +26,13 @@ | |||
26 | #include <net/checksum.h> | 26 | #include <net/checksum.h> |
27 | #include <net/protocol.h> | 27 | #include <net/protocol.h> |
28 | #include <net/netfilter/nf_nat.h> | 28 | #include <net/netfilter/nf_nat.h> |
29 | 29 | #include <net/netfilter/ipv4/nf_nat_redirect.h> | |
30 | static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; | 30 | #include <net/netfilter/ipv6/nf_nat_redirect.h> |
31 | 31 | ||
32 | static unsigned int | 32 | static unsigned int |
33 | redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par) | 33 | redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
34 | { | 34 | { |
35 | const struct nf_nat_range *range = par->targinfo; | 35 | return nf_nat_redirect_ipv6(skb, par->targinfo, par->hooknum); |
36 | struct nf_nat_range newrange; | ||
37 | struct in6_addr newdst; | ||
38 | enum ip_conntrack_info ctinfo; | ||
39 | struct nf_conn *ct; | ||
40 | |||
41 | ct = nf_ct_get(skb, &ctinfo); | ||
42 | if (par->hooknum == NF_INET_LOCAL_OUT) | ||
43 | newdst = loopback_addr; | ||
44 | else { | ||
45 | struct inet6_dev *idev; | ||
46 | struct inet6_ifaddr *ifa; | ||
47 | bool addr = false; | ||
48 | |||
49 | rcu_read_lock(); | ||
50 | idev = __in6_dev_get(skb->dev); | ||
51 | if (idev != NULL) { | ||
52 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
53 | newdst = ifa->addr; | ||
54 | addr = true; | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | rcu_read_unlock(); | ||
59 | |||
60 | if (!addr) | ||
61 | return NF_DROP; | ||
62 | } | ||
63 | |||
64 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
65 | newrange.min_addr.in6 = newdst; | ||
66 | newrange.max_addr.in6 = newdst; | ||
67 | newrange.min_proto = range->min_proto; | ||
68 | newrange.max_proto = range->max_proto; | ||
69 | |||
70 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | ||
71 | } | 36 | } |
72 | 37 | ||
73 | static int redirect_tg6_checkentry(const struct xt_tgchk_param *par) | 38 | static int redirect_tg6_checkentry(const struct xt_tgchk_param *par) |
@@ -98,48 +63,7 @@ static int redirect_tg4_check(const struct xt_tgchk_param *par) | |||
98 | static unsigned int | 63 | static unsigned int |
99 | redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par) | 64 | redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par) |
100 | { | 65 | { |
101 | struct nf_conn *ct; | 66 | return nf_nat_redirect_ipv4(skb, par->targinfo, par->hooknum); |
102 | enum ip_conntrack_info ctinfo; | ||
103 | __be32 newdst; | ||
104 | const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; | ||
105 | struct nf_nat_range newrange; | ||
106 | |||
107 | NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || | ||
108 | par->hooknum == NF_INET_LOCAL_OUT); | ||
109 | |||
110 | ct = nf_ct_get(skb, &ctinfo); | ||
111 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); | ||
112 | |||
113 | /* Local packets: make them go to loopback */ | ||
114 | if (par->hooknum == NF_INET_LOCAL_OUT) | ||
115 | newdst = htonl(0x7F000001); | ||
116 | else { | ||
117 | struct in_device *indev; | ||
118 | struct in_ifaddr *ifa; | ||
119 | |||
120 | newdst = 0; | ||
121 | |||
122 | rcu_read_lock(); | ||
123 | indev = __in_dev_get_rcu(skb->dev); | ||
124 | if (indev && (ifa = indev->ifa_list)) | ||
125 | newdst = ifa->ifa_local; | ||
126 | rcu_read_unlock(); | ||
127 | |||
128 | if (!newdst) | ||
129 | return NF_DROP; | ||
130 | } | ||
131 | |||
132 | /* Transfer from original range. */ | ||
133 | memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); | ||
134 | memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); | ||
135 | newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; | ||
136 | newrange.min_addr.ip = newdst; | ||
137 | newrange.max_addr.ip = newdst; | ||
138 | newrange.min_proto = mr->range[0].min; | ||
139 | newrange.max_proto = mr->range[0].max; | ||
140 | |||
141 | /* Hand modified range to generic setup. */ | ||
142 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | ||
143 | } | 67 | } |
144 | 68 | ||
145 | static struct xt_target redirect_tg_reg[] __read_mostly = { | 69 | static struct xt_target redirect_tg_reg[] __read_mostly = { |
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index fbc66bb250d5..29ba6218a820 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c | |||
@@ -134,6 +134,7 @@ static bool add_hlist(struct hlist_head *head, | |||
134 | static unsigned int check_hlist(struct net *net, | 134 | static unsigned int check_hlist(struct net *net, |
135 | struct hlist_head *head, | 135 | struct hlist_head *head, |
136 | const struct nf_conntrack_tuple *tuple, | 136 | const struct nf_conntrack_tuple *tuple, |
137 | u16 zone, | ||
137 | bool *addit) | 138 | bool *addit) |
138 | { | 139 | { |
139 | const struct nf_conntrack_tuple_hash *found; | 140 | const struct nf_conntrack_tuple_hash *found; |
@@ -147,8 +148,7 @@ static unsigned int check_hlist(struct net *net, | |||
147 | 148 | ||
148 | /* check the saved connections */ | 149 | /* check the saved connections */ |
149 | hlist_for_each_entry_safe(conn, n, head, node) { | 150 | hlist_for_each_entry_safe(conn, n, head, node) { |
150 | found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, | 151 | found = nf_conntrack_find_get(net, zone, &conn->tuple); |
151 | &conn->tuple); | ||
152 | if (found == NULL) { | 152 | if (found == NULL) { |
153 | hlist_del(&conn->node); | 153 | hlist_del(&conn->node); |
154 | kmem_cache_free(connlimit_conn_cachep, conn); | 154 | kmem_cache_free(connlimit_conn_cachep, conn); |
@@ -201,7 +201,7 @@ static unsigned int | |||
201 | count_tree(struct net *net, struct rb_root *root, | 201 | count_tree(struct net *net, struct rb_root *root, |
202 | const struct nf_conntrack_tuple *tuple, | 202 | const struct nf_conntrack_tuple *tuple, |
203 | const union nf_inet_addr *addr, const union nf_inet_addr *mask, | 203 | const union nf_inet_addr *addr, const union nf_inet_addr *mask, |
204 | u8 family) | 204 | u8 family, u16 zone) |
205 | { | 205 | { |
206 | struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; | 206 | struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; |
207 | struct rb_node **rbnode, *parent; | 207 | struct rb_node **rbnode, *parent; |
@@ -229,7 +229,7 @@ count_tree(struct net *net, struct rb_root *root, | |||
229 | } else { | 229 | } else { |
230 | /* same source network -> be counted! */ | 230 | /* same source network -> be counted! */ |
231 | unsigned int count; | 231 | unsigned int count; |
232 | count = check_hlist(net, &rbconn->hhead, tuple, &addit); | 232 | count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit); |
233 | 233 | ||
234 | tree_nodes_free(root, gc_nodes, gc_count); | 234 | tree_nodes_free(root, gc_nodes, gc_count); |
235 | if (!addit) | 235 | if (!addit) |
@@ -245,7 +245,7 @@ count_tree(struct net *net, struct rb_root *root, | |||
245 | continue; | 245 | continue; |
246 | 246 | ||
247 | /* only used for GC on hhead, retval and 'addit' ignored */ | 247 | /* only used for GC on hhead, retval and 'addit' ignored */ |
248 | check_hlist(net, &rbconn->hhead, tuple, &addit); | 248 | check_hlist(net, &rbconn->hhead, tuple, zone, &addit); |
249 | if (hlist_empty(&rbconn->hhead)) | 249 | if (hlist_empty(&rbconn->hhead)) |
250 | gc_nodes[gc_count++] = rbconn; | 250 | gc_nodes[gc_count++] = rbconn; |
251 | } | 251 | } |
@@ -290,7 +290,7 @@ static int count_them(struct net *net, | |||
290 | const struct nf_conntrack_tuple *tuple, | 290 | const struct nf_conntrack_tuple *tuple, |
291 | const union nf_inet_addr *addr, | 291 | const union nf_inet_addr *addr, |
292 | const union nf_inet_addr *mask, | 292 | const union nf_inet_addr *mask, |
293 | u_int8_t family) | 293 | u_int8_t family, u16 zone) |
294 | { | 294 | { |
295 | struct rb_root *root; | 295 | struct rb_root *root; |
296 | int count; | 296 | int count; |
@@ -306,7 +306,7 @@ static int count_them(struct net *net, | |||
306 | 306 | ||
307 | spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); | 307 | spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); |
308 | 308 | ||
309 | count = count_tree(net, root, tuple, addr, mask, family); | 309 | count = count_tree(net, root, tuple, addr, mask, family, zone); |
310 | 310 | ||
311 | spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); | 311 | spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); |
312 | 312 | ||
@@ -324,13 +324,16 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
324 | enum ip_conntrack_info ctinfo; | 324 | enum ip_conntrack_info ctinfo; |
325 | const struct nf_conn *ct; | 325 | const struct nf_conn *ct; |
326 | unsigned int connections; | 326 | unsigned int connections; |
327 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
327 | 328 | ||
328 | ct = nf_ct_get(skb, &ctinfo); | 329 | ct = nf_ct_get(skb, &ctinfo); |
329 | if (ct != NULL) | 330 | if (ct != NULL) { |
330 | tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | 331 | tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
331 | else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), | 332 | zone = nf_ct_zone(ct); |
332 | par->family, &tuple)) | 333 | } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), |
334 | par->family, &tuple)) { | ||
333 | goto hotdrop; | 335 | goto hotdrop; |
336 | } | ||
334 | 337 | ||
335 | if (par->family == NFPROTO_IPV6) { | 338 | if (par->family == NFPROTO_IPV6) { |
336 | const struct ipv6hdr *iph = ipv6_hdr(skb); | 339 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
@@ -343,7 +346,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
343 | } | 346 | } |
344 | 347 | ||
345 | connections = count_them(net, info->data, tuple_ptr, &addr, | 348 | connections = count_them(net, info->data, tuple_ptr, &addr, |
346 | &info->mask, par->family); | 349 | &info->mask, par->family, zone); |
347 | if (connections == 0) | 350 | if (connections == 0) |
348 | /* kmalloc failed, drop it entirely */ | 351 | /* kmalloc failed, drop it entirely */ |
349 | goto hotdrop; | 352 | goto hotdrop; |