aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-12-05 23:56:46 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-05 23:56:46 -0500
commit244ebd9f8fa8beb7b37bdeebd6c5308b61f98aef (patch)
tree8b0a72056747f0bb9232fdafb480b0501dc83734 /net
parentddd5c50f9bec7ffab5d28c5dd244db8a4c3f27e7 (diff)
parentcac3763967362ace7996532ad3933f493a928a1b (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following batch contains netfilter updates for net-next. Basically, enhancements for xt_recent, skip zeroing of timer in conntrack, fix linking problem with recent redirect support for nf_tables, ipset updates and a couple of cleanups. More specifically, they are: 1) Rise maximum number per IP address to be remembered in xt_recent while retaining backward compatibility, from Florian Westphal. 2) Skip zeroing timer area in nf_conn objects, also from Florian. 3) Inspect IPv4 and IPv6 traffic from the bridge to allow filtering using using meta l4proto and transport layer header, from Alvaro Neira. 4) Fix linking problems in the new redirect support when CONFIG_IPV6=n and IP6_NF_IPTABLES=n. And ipset updates from Jozsef Kadlecsik: 5) Support updating element extensions when the set is full (fixes netfilter bugzilla id 880). 6) Fix set match with 32-bits userspace / 64-bits kernel. 7) Indicate explicitly when /0 networks are supported in ipset. 8) Simplify cidr handling for hash:*net* types. 9) Allocate the proper size of memory when /0 networks are supported. 10) Explicitly add padding elements to hash:net,net and hash:net,port, because the elements must be u32 sized for the used hash function. Jozsef is also cooking ipset RCU conversion which should land soon if they reach the merge window in time. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c88
-rw-r--r--net/bridge/netfilter/nft_reject_bridge.c52
-rw-r--r--net/ipv4/netfilter/Kconfig8
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/nft_redir_ipv4.c2
-rw-r--r--net/ipv6/netfilter/Kconfig8
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/nf_log_ipv6.c2
-rw-r--r--net/ipv6/netfilter/nf_nat_redirect_ipv6.c75
-rw-r--r--net/ipv6/netfilter/nft_redir_ipv6.c2
-rw-r--r--net/netfilter/Kconfig10
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h101
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c1
-rw-r--r--net/netfilter/ipset/ip_set_hash_netnet.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_netportnet.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c11
-rw-r--r--net/netfilter/nf_nat_redirect.c (renamed from net/ipv4/netfilter/nf_nat_redirect_ipv4.c)47
-rw-r--r--net/netfilter/xt_REDIRECT.c3
-rw-r--r--net/netfilter/xt_recent.c64
-rw-r--r--net/netfilter/xt_set.c73
21 files changed, 326 insertions, 228 deletions
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c
index 074c557ab505..19473a9371b8 100644
--- a/net/bridge/netfilter/nf_tables_bridge.c
+++ b/net/bridge/netfilter/nf_tables_bridge.c
@@ -13,6 +13,82 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/netfilter_bridge.h> 14#include <linux/netfilter_bridge.h>
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nf_tables_bridge.h>
17#include <linux/ip.h>
18#include <linux/ipv6.h>
19#include <net/netfilter/nf_tables_ipv4.h>
20#include <net/netfilter/nf_tables_ipv6.h>
21
22int nft_bridge_iphdr_validate(struct sk_buff *skb)
23{
24 struct iphdr *iph;
25 u32 len;
26
27 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
28 return 0;
29
30 iph = ip_hdr(skb);
31 if (iph->ihl < 5 || iph->version != 4)
32 return 0;
33
34 len = ntohs(iph->tot_len);
35 if (skb->len < len)
36 return 0;
37 else if (len < (iph->ihl*4))
38 return 0;
39
40 if (!pskb_may_pull(skb, iph->ihl*4))
41 return 0;
42
43 return 1;
44}
45EXPORT_SYMBOL_GPL(nft_bridge_iphdr_validate);
46
47int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
48{
49 struct ipv6hdr *hdr;
50 u32 pkt_len;
51
52 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
53 return 0;
54
55 hdr = ipv6_hdr(skb);
56 if (hdr->version != 6)
57 return 0;
58
59 pkt_len = ntohs(hdr->payload_len);
60 if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
61 return 0;
62
63 return 1;
64}
65EXPORT_SYMBOL_GPL(nft_bridge_ip6hdr_validate);
66
67static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
68 const struct nf_hook_ops *ops,
69 struct sk_buff *skb,
70 const struct net_device *in,
71 const struct net_device *out)
72{
73 if (nft_bridge_iphdr_validate(skb))
74 nft_set_pktinfo_ipv4(pkt, ops, skb, in, out);
75 else
76 nft_set_pktinfo(pkt, ops, skb, in, out);
77}
78
79static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
80 const struct nf_hook_ops *ops,
81 struct sk_buff *skb,
82 const struct net_device *in,
83 const struct net_device *out)
84{
85#if IS_ENABLED(CONFIG_IPV6)
86 if (nft_bridge_ip6hdr_validate(skb) &&
87 nft_set_pktinfo_ipv6(pkt, ops, skb, in, out) == 0)
88 return;
89#endif
90 nft_set_pktinfo(pkt, ops, skb, in, out);
91}
16 92
17static unsigned int 93static unsigned int
18nft_do_chain_bridge(const struct nf_hook_ops *ops, 94nft_do_chain_bridge(const struct nf_hook_ops *ops,
@@ -23,7 +99,17 @@ nft_do_chain_bridge(const struct nf_hook_ops *ops,
23{ 99{
24 struct nft_pktinfo pkt; 100 struct nft_pktinfo pkt;
25 101
26 nft_set_pktinfo(&pkt, ops, skb, in, out); 102 switch (eth_hdr(skb)->h_proto) {
103 case htons(ETH_P_IP):
104 nft_bridge_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
105 break;
106 case htons(ETH_P_IPV6):
107 nft_bridge_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
108 break;
109 default:
110 nft_set_pktinfo(&pkt, ops, skb, in, out);
111 break;
112 }
27 113
28 return nft_do_chain(&pkt, ops); 114 return nft_do_chain(&pkt, ops);
29} 115}
diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c
index 48da2c54a69e..b0330aecbf97 100644
--- a/net/bridge/netfilter/nft_reject_bridge.c
+++ b/net/bridge/netfilter/nft_reject_bridge.c
@@ -14,6 +14,7 @@
14#include <linux/netfilter/nf_tables.h> 14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nft_reject.h> 16#include <net/netfilter/nft_reject.h>
17#include <net/netfilter/nf_tables_bridge.h>
17#include <net/netfilter/ipv4/nf_reject.h> 18#include <net/netfilter/ipv4/nf_reject.h>
18#include <net/netfilter/ipv6/nf_reject.h> 19#include <net/netfilter/ipv6/nf_reject.h>
19#include <linux/ip.h> 20#include <linux/ip.h>
@@ -35,30 +36,6 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
35 skb_pull(nskb, ETH_HLEN); 36 skb_pull(nskb, ETH_HLEN);
36} 37}
37 38
38static int nft_reject_iphdr_validate(struct sk_buff *oldskb)
39{
40 struct iphdr *iph;
41 u32 len;
42
43 if (!pskb_may_pull(oldskb, sizeof(struct iphdr)))
44 return 0;
45
46 iph = ip_hdr(oldskb);
47 if (iph->ihl < 5 || iph->version != 4)
48 return 0;
49
50 len = ntohs(iph->tot_len);
51 if (oldskb->len < len)
52 return 0;
53 else if (len < (iph->ihl*4))
54 return 0;
55
56 if (!pskb_may_pull(oldskb, iph->ihl*4))
57 return 0;
58
59 return 1;
60}
61
62static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, int hook) 39static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, int hook)
63{ 40{
64 struct sk_buff *nskb; 41 struct sk_buff *nskb;
@@ -66,7 +43,7 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, int hook)
66 const struct tcphdr *oth; 43 const struct tcphdr *oth;
67 struct tcphdr _oth; 44 struct tcphdr _oth;
68 45
69 if (!nft_reject_iphdr_validate(oldskb)) 46 if (!nft_bridge_iphdr_validate(oldskb))
70 return; 47 return;
71 48
72 oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); 49 oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
@@ -101,7 +78,7 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, int hook,
101 void *payload; 78 void *payload;
102 __wsum csum; 79 __wsum csum;
103 80
104 if (!nft_reject_iphdr_validate(oldskb)) 81 if (!nft_bridge_iphdr_validate(oldskb))
105 return; 82 return;
106 83
107 /* IP header checks: fragment. */ 84 /* IP header checks: fragment. */
@@ -146,25 +123,6 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, int hook,
146 br_deliver(br_port_get_rcu(oldskb->dev), nskb); 123 br_deliver(br_port_get_rcu(oldskb->dev), nskb);
147} 124}
148 125
149static int nft_reject_ip6hdr_validate(struct sk_buff *oldskb)
150{
151 struct ipv6hdr *hdr;
152 u32 pkt_len;
153
154 if (!pskb_may_pull(oldskb, sizeof(struct ipv6hdr)))
155 return 0;
156
157 hdr = ipv6_hdr(oldskb);
158 if (hdr->version != 6)
159 return 0;
160
161 pkt_len = ntohs(hdr->payload_len);
162 if (pkt_len + sizeof(struct ipv6hdr) > oldskb->len)
163 return 0;
164
165 return 1;
166}
167
168static void nft_reject_br_send_v6_tcp_reset(struct net *net, 126static void nft_reject_br_send_v6_tcp_reset(struct net *net,
169 struct sk_buff *oldskb, int hook) 127 struct sk_buff *oldskb, int hook)
170{ 128{
@@ -174,7 +132,7 @@ static void nft_reject_br_send_v6_tcp_reset(struct net *net,
174 unsigned int otcplen; 132 unsigned int otcplen;
175 struct ipv6hdr *nip6h; 133 struct ipv6hdr *nip6h;
176 134
177 if (!nft_reject_ip6hdr_validate(oldskb)) 135 if (!nft_bridge_ip6hdr_validate(oldskb))
178 return; 136 return;
179 137
180 oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook); 138 oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook);
@@ -207,7 +165,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
207 unsigned int len; 165 unsigned int len;
208 void *payload; 166 void *payload;
209 167
210 if (!nft_reject_ip6hdr_validate(oldskb)) 168 if (!nft_bridge_ip6hdr_validate(oldskb))
211 return; 169 return;
212 170
213 /* Include "As much of invoking packet as possible without the ICMPv6 171 /* Include "As much of invoking packet as possible without the ICMPv6
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 8358b2da1549..59f883d9cadf 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -104,12 +104,6 @@ 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
107config 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
113config NFT_MASQ_IPV4 107config NFT_MASQ_IPV4
114 tristate "IPv4 masquerading support for nf_tables" 108 tristate "IPv4 masquerading support for nf_tables"
115 depends on NF_TABLES_IPV4 109 depends on NF_TABLES_IPV4
@@ -123,7 +117,7 @@ config NFT_REDIR_IPV4
123 tristate "IPv4 redirect support for nf_tables" 117 tristate "IPv4 redirect support for nf_tables"
124 depends on NF_TABLES_IPV4 118 depends on NF_TABLES_IPV4
125 depends on NFT_REDIR 119 depends on NFT_REDIR
126 select NF_NAT_REDIRECT_IPV4 120 select NF_NAT_REDIRECT
127 help 121 help
128 This is the expression that provides IPv4 redirect support for 122 This is the expression that provides IPv4 redirect support for
129 nf_tables. 123 nf_tables.
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 902bcd1597bb..7fe6c703528f 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
31obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 31obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
32obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 32obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
33obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o 33obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o
34obj-$(CONFIG_NF_NAT_REDIRECT_IPV4) += nf_nat_redirect_ipv4.o
35 34
36# NAT protocols (nf_nat) 35# NAT protocols (nf_nat)
37obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 36obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
diff --git a/net/ipv4/netfilter/nft_redir_ipv4.c b/net/ipv4/netfilter/nft_redir_ipv4.c
index 643c5967aa27..ff2d23d8c87a 100644
--- a/net/ipv4/netfilter/nft_redir_ipv4.c
+++ b/net/ipv4/netfilter/nft_redir_ipv4.c
@@ -14,7 +14,7 @@
14#include <linux/netfilter/nf_tables.h> 14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/ipv4/nf_nat_redirect.h> 17#include <net/netfilter/nf_nat_redirect.h>
18#include <net/netfilter/nft_redir.h> 18#include <net/netfilter/nft_redir.h>
19 19
20static void nft_redir_ipv4_eval(const struct nft_expr *expr, 20static void nft_redir_ipv4_eval(const struct nft_expr *expr,
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 0dbe5c7953e5..a069822936e6 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -82,12 +82,6 @@ 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
85config 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
91config NFT_MASQ_IPV6 85config NFT_MASQ_IPV6
92 tristate "IPv6 masquerade support for nf_tables" 86 tristate "IPv6 masquerade support for nf_tables"
93 depends on NF_TABLES_IPV6 87 depends on NF_TABLES_IPV6
@@ -101,7 +95,7 @@ config NFT_REDIR_IPV6
101 tristate "IPv6 redirect support for nf_tables" 95 tristate "IPv6 redirect support for nf_tables"
102 depends on NF_TABLES_IPV6 96 depends on NF_TABLES_IPV6
103 depends on NFT_REDIR 97 depends on NFT_REDIR
104 select NF_NAT_REDIRECT_IPV6 98 select NF_NAT_REDIRECT
105 help 99 help
106 This is the expression that provides IPv4 redirect support for 100 This is the expression that provides IPv4 redirect support for
107 nf_tables. 101 nf_tables.
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index d2ac9f5f212c..c36e0a5490de 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o 19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o
20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o 20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
21obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o 21obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o
22obj-$(CONFIG_NF_NAT_REDIRECT_IPV6) += nf_nat_redirect_ipv6.o
23 22
24# defrag 23# defrag
25nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 24nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/nf_log_ipv6.c b/net/ipv6/netfilter/nf_log_ipv6.c
index 7fc34d1681a1..ddf07e6f59d7 100644
--- a/net/ipv6/netfilter/nf_log_ipv6.c
+++ b/net/ipv6/netfilter/nf_log_ipv6.c
@@ -422,6 +422,6 @@ module_init(nf_log_ipv6_init);
422module_exit(nf_log_ipv6_exit); 422module_exit(nf_log_ipv6_exit);
423 423
424MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 424MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
425MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); 425MODULE_DESCRIPTION("Netfilter IPv6 packet logging");
426MODULE_LICENSE("GPL"); 426MODULE_LICENSE("GPL");
427MODULE_ALIAS_NF_LOGGER(AF_INET6, 0); 427MODULE_ALIAS_NF_LOGGER(AF_INET6, 0);
diff --git a/net/ipv6/netfilter/nf_nat_redirect_ipv6.c b/net/ipv6/netfilter/nf_nat_redirect_ipv6.c
deleted file mode 100644
index ea1308aeb048..000000000000
--- a/net/ipv6/netfilter/nf_nat_redirect_ipv6.c
+++ /dev/null
@@ -1,75 +0,0 @@
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
30static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
31
32unsigned int
33nf_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}
72EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6);
73
74MODULE_LICENSE("GPL");
75MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv6/netfilter/nft_redir_ipv6.c b/net/ipv6/netfilter/nft_redir_ipv6.c
index 83420eeaad1c..2433a6bfb191 100644
--- a/net/ipv6/netfilter/nft_redir_ipv6.c
+++ b/net/ipv6/netfilter/nft_redir_ipv6.c
@@ -15,7 +15,7 @@
15#include <net/netfilter/nf_tables.h> 15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nft_redir.h> 17#include <net/netfilter/nft_redir.h>
18#include <net/netfilter/ipv6/nf_nat_redirect.h> 18#include <net/netfilter/nf_nat_redirect.h>
19 19
20static void nft_redir_ipv6_eval(const struct nft_expr *expr, 20static void nft_redir_ipv6_eval(const struct nft_expr *expr,
21 struct nft_data data[NFT_REG_MAX + 1], 21 struct nft_data data[NFT_REG_MAX + 1],
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 57f15a9aa481..b02660fa9eb0 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -411,6 +411,13 @@ config NF_NAT_TFTP
411 depends on NF_CONNTRACK && NF_NAT 411 depends on NF_CONNTRACK && NF_NAT
412 default NF_NAT && NF_CONNTRACK_TFTP 412 default NF_NAT && NF_CONNTRACK_TFTP
413 413
414config NF_NAT_REDIRECT
415 tristate "IPv4/IPv6 redirect support"
416 depends on NF_NAT
417 help
418 This is the kernel functionality to redirect packets to local
419 machine through NAT.
420
414config NETFILTER_SYNPROXY 421config NETFILTER_SYNPROXY
415 tristate 422 tristate
416 423
@@ -844,8 +851,7 @@ config NETFILTER_XT_TARGET_RATEEST
844config NETFILTER_XT_TARGET_REDIRECT 851config NETFILTER_XT_TARGET_REDIRECT
845 tristate "REDIRECT target support" 852 tristate "REDIRECT target support"
846 depends on NF_NAT 853 depends on NF_NAT
847 select NF_NAT_REDIRECT_IPV4 if NF_NAT_IPV4 854 select NF_NAT_REDIRECT
848 select NF_NAT_REDIRECT_IPV6 if NF_NAT_IPV6
849 ---help--- 855 ---help---
850 REDIRECT is a special case of NAT: all incoming connections are 856 REDIRECT is a special case of NAT: all incoming connections are
851 mapped onto the incoming interface's address, causing the packets to 857 mapped onto the incoming interface's address, causing the packets to
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index f3eb4680f2ec..89f73a9e9874 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -51,6 +51,7 @@ nf_nat-y := nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \
51obj-$(CONFIG_NF_LOG_COMMON) += nf_log_common.o 51obj-$(CONFIG_NF_LOG_COMMON) += nf_log_common.o
52 52
53obj-$(CONFIG_NF_NAT) += nf_nat.o 53obj-$(CONFIG_NF_NAT) += nf_nat.o
54obj-$(CONFIG_NF_NAT_REDIRECT) += nf_nat_redirect.o
54 55
55# NAT protocols (nf_nat) 56# NAT protocols (nf_nat)
56obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o 57obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index fee7c64e4dd1..974ff386db0f 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -147,16 +147,22 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
147#else 147#else
148#define __CIDR(cidr, i) (cidr) 148#define __CIDR(cidr, i) (cidr)
149#endif 149#endif
150
151/* cidr + 1 is stored in net_prefixes to support /0 */
152#define SCIDR(cidr, i) (__CIDR(cidr, i) + 1)
153
150#ifdef IP_SET_HASH_WITH_NETS_PACKED 154#ifdef IP_SET_HASH_WITH_NETS_PACKED
151/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */ 155/* When cidr is packed with nomatch, cidr - 1 is stored in the data entry */
152#define CIDR(cidr, i) (__CIDR(cidr, i) + 1) 156#define GCIDR(cidr, i) (__CIDR(cidr, i) + 1)
157#define NCIDR(cidr) (cidr)
153#else 158#else
154#define CIDR(cidr, i) (__CIDR(cidr, i)) 159#define GCIDR(cidr, i) (__CIDR(cidr, i))
160#define NCIDR(cidr) (cidr - 1)
155#endif 161#endif
156 162
157#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) 163#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
158 164
159#ifdef IP_SET_HASH_WITH_MULTI 165#ifdef IP_SET_HASH_WITH_NET0
160#define NLEN(family) (SET_HOST_MASK(family) + 1) 166#define NLEN(family) (SET_HOST_MASK(family) + 1)
161#else 167#else
162#define NLEN(family) SET_HOST_MASK(family) 168#define NLEN(family) SET_HOST_MASK(family)
@@ -292,24 +298,22 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
292 int i, j; 298 int i, j;
293 299
294 /* Add in increasing prefix order, so larger cidr first */ 300 /* Add in increasing prefix order, so larger cidr first */
295 for (i = 0, j = -1; i < nets_length && h->nets[i].nets[n]; i++) { 301 for (i = 0, j = -1; i < nets_length && h->nets[i].cidr[n]; i++) {
296 if (j != -1) 302 if (j != -1)
297 continue; 303 continue;
298 else if (h->nets[i].cidr[n] < cidr) 304 else if (h->nets[i].cidr[n] < cidr)
299 j = i; 305 j = i;
300 else if (h->nets[i].cidr[n] == cidr) { 306 else if (h->nets[i].cidr[n] == cidr) {
301 h->nets[i].nets[n]++; 307 h->nets[cidr - 1].nets[n]++;
302 return; 308 return;
303 } 309 }
304 } 310 }
305 if (j != -1) { 311 if (j != -1) {
306 for (; i > j; i--) { 312 for (; i > j; i--)
307 h->nets[i].cidr[n] = h->nets[i - 1].cidr[n]; 313 h->nets[i].cidr[n] = h->nets[i - 1].cidr[n];
308 h->nets[i].nets[n] = h->nets[i - 1].nets[n];
309 }
310 } 314 }
311 h->nets[i].cidr[n] = cidr; 315 h->nets[i].cidr[n] = cidr;
312 h->nets[i].nets[n] = 1; 316 h->nets[cidr - 1].nets[n] = 1;
313} 317}
314 318
315static void 319static void
@@ -320,16 +324,12 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
320 for (i = 0; i < nets_length; i++) { 324 for (i = 0; i < nets_length; i++) {
321 if (h->nets[i].cidr[n] != cidr) 325 if (h->nets[i].cidr[n] != cidr)
322 continue; 326 continue;
323 if (h->nets[i].nets[n] > 1 || i == net_end || 327 h->nets[cidr -1].nets[n]--;
324 h->nets[i + 1].nets[n] == 0) { 328 if (h->nets[cidr -1].nets[n] > 0)
325 h->nets[i].nets[n]--;
326 return; 329 return;
327 } 330 for (j = i; j < net_end && h->nets[j].cidr[n]; j++)
328 for (j = i; j < net_end && h->nets[j].nets[n]; j++) {
329 h->nets[j].cidr[n] = h->nets[j + 1].cidr[n]; 331 h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
330 h->nets[j].nets[n] = h->nets[j + 1].nets[n]; 332 h->nets[j].cidr[n] = 0;
331 }
332 h->nets[j].nets[n] = 0;
333 return; 333 return;
334 } 334 }
335} 335}
@@ -486,7 +486,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
486 pr_debug("expired %u/%u\n", i, j); 486 pr_debug("expired %u/%u\n", i, j);
487#ifdef IP_SET_HASH_WITH_NETS 487#ifdef IP_SET_HASH_WITH_NETS
488 for (k = 0; k < IPSET_NET_COUNT; k++) 488 for (k = 0; k < IPSET_NET_COUNT; k++)
489 mtype_del_cidr(h, CIDR(data->cidr, k), 489 mtype_del_cidr(h, SCIDR(data->cidr, k),
490 nets_length, k); 490 nets_length, k);
491#endif 491#endif
492 ip_set_ext_destroy(set, data); 492 ip_set_ext_destroy(set, data);
@@ -633,29 +633,6 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
633 bool flag_exist = flags & IPSET_FLAG_EXIST; 633 bool flag_exist = flags & IPSET_FLAG_EXIST;
634 u32 key, multi = 0; 634 u32 key, multi = 0;
635 635
636 if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) {
637 rcu_read_lock_bh();
638 t = rcu_dereference_bh(h->table);
639 key = HKEY(value, h->initval, t->htable_bits);
640 n = hbucket(t,key);
641 if (n->pos) {
642 /* Choosing the first entry in the array to replace */
643 j = 0;
644 goto reuse_slot;
645 }
646 rcu_read_unlock_bh();
647 }
648 if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
649 /* FIXME: when set is full, we slow down here */
650 mtype_expire(set, h, NLEN(set->family), set->dsize);
651
652 if (h->elements >= h->maxelem) {
653 if (net_ratelimit())
654 pr_warn("Set %s is full, maxelem %u reached\n",
655 set->name, h->maxelem);
656 return -IPSET_ERR_HASH_FULL;
657 }
658
659 rcu_read_lock_bh(); 636 rcu_read_lock_bh();
660 t = rcu_dereference_bh(h->table); 637 t = rcu_dereference_bh(h->table);
661 key = HKEY(value, h->initval, t->htable_bits); 638 key = HKEY(value, h->initval, t->htable_bits);
@@ -680,15 +657,32 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
680 j != AHASH_MAX(h) + 1) 657 j != AHASH_MAX(h) + 1)
681 j = i; 658 j = i;
682 } 659 }
660 if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set) && n->pos) {
661 /* Choosing the first entry in the array to replace */
662 j = 0;
663 goto reuse_slot;
664 }
665 if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
666 /* FIXME: when set is full, we slow down here */
667 mtype_expire(set, h, NLEN(set->family), set->dsize);
668
669 if (h->elements >= h->maxelem) {
670 if (net_ratelimit())
671 pr_warn("Set %s is full, maxelem %u reached\n",
672 set->name, h->maxelem);
673 ret = -IPSET_ERR_HASH_FULL;
674 goto out;
675 }
676
683reuse_slot: 677reuse_slot:
684 if (j != AHASH_MAX(h) + 1) { 678 if (j != AHASH_MAX(h) + 1) {
685 /* Fill out reused slot */ 679 /* Fill out reused slot */
686 data = ahash_data(n, j, set->dsize); 680 data = ahash_data(n, j, set->dsize);
687#ifdef IP_SET_HASH_WITH_NETS 681#ifdef IP_SET_HASH_WITH_NETS
688 for (i = 0; i < IPSET_NET_COUNT; i++) { 682 for (i = 0; i < IPSET_NET_COUNT; i++) {
689 mtype_del_cidr(h, CIDR(data->cidr, i), 683 mtype_del_cidr(h, SCIDR(data->cidr, i),
690 NLEN(set->family), i); 684 NLEN(set->family), i);
691 mtype_add_cidr(h, CIDR(d->cidr, i), 685 mtype_add_cidr(h, SCIDR(d->cidr, i),
692 NLEN(set->family), i); 686 NLEN(set->family), i);
693 } 687 }
694#endif 688#endif
@@ -705,7 +699,7 @@ reuse_slot:
705 data = ahash_data(n, n->pos++, set->dsize); 699 data = ahash_data(n, n->pos++, set->dsize);
706#ifdef IP_SET_HASH_WITH_NETS 700#ifdef IP_SET_HASH_WITH_NETS
707 for (i = 0; i < IPSET_NET_COUNT; i++) 701 for (i = 0; i < IPSET_NET_COUNT; i++)
708 mtype_add_cidr(h, CIDR(d->cidr, i), NLEN(set->family), 702 mtype_add_cidr(h, SCIDR(d->cidr, i), NLEN(set->family),
709 i); 703 i);
710#endif 704#endif
711 h->elements++; 705 h->elements++;
@@ -766,7 +760,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
766 h->elements--; 760 h->elements--;
767#ifdef IP_SET_HASH_WITH_NETS 761#ifdef IP_SET_HASH_WITH_NETS
768 for (j = 0; j < IPSET_NET_COUNT; j++) 762 for (j = 0; j < IPSET_NET_COUNT; j++)
769 mtype_del_cidr(h, CIDR(d->cidr, j), NLEN(set->family), 763 mtype_del_cidr(h, SCIDR(d->cidr, j), NLEN(set->family),
770 j); 764 j);
771#endif 765#endif
772 ip_set_ext_destroy(set, data); 766 ip_set_ext_destroy(set, data);
@@ -827,15 +821,15 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
827 u8 nets_length = NLEN(set->family); 821 u8 nets_length = NLEN(set->family);
828 822
829 pr_debug("test by nets\n"); 823 pr_debug("test by nets\n");
830 for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) { 824 for (; j < nets_length && h->nets[j].cidr[0] && !multi; j++) {
831#if IPSET_NET_COUNT == 2 825#if IPSET_NET_COUNT == 2
832 mtype_data_reset_elem(d, &orig); 826 mtype_data_reset_elem(d, &orig);
833 mtype_data_netmask(d, h->nets[j].cidr[0], false); 827 mtype_data_netmask(d, NCIDR(h->nets[j].cidr[0]), false);
834 for (k = 0; k < nets_length && h->nets[k].nets[1] && !multi; 828 for (k = 0; k < nets_length && h->nets[k].cidr[1] && !multi;
835 k++) { 829 k++) {
836 mtype_data_netmask(d, h->nets[k].cidr[1], true); 830 mtype_data_netmask(d, NCIDR(h->nets[k].cidr[1]), true);
837#else 831#else
838 mtype_data_netmask(d, h->nets[j].cidr[0]); 832 mtype_data_netmask(d, NCIDR(h->nets[j].cidr[0]));
839#endif 833#endif
840 key = HKEY(d, h->initval, t->htable_bits); 834 key = HKEY(d, h->initval, t->htable_bits);
841 n = hbucket(t, key); 835 n = hbucket(t, key);
@@ -883,7 +877,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
883 /* If we test an IP address and not a network address, 877 /* If we test an IP address and not a network address,
884 * try all possible network sizes */ 878 * try all possible network sizes */
885 for (i = 0; i < IPSET_NET_COUNT; i++) 879 for (i = 0; i < IPSET_NET_COUNT; i++)
886 if (CIDR(d->cidr, i) != SET_HOST_MASK(set->family)) 880 if (GCIDR(d->cidr, i) != SET_HOST_MASK(set->family))
887 break; 881 break;
888 if (i == IPSET_NET_COUNT) { 882 if (i == IPSET_NET_COUNT) {
889 ret = mtype_test_cidrs(set, d, ext, mext, flags); 883 ret = mtype_test_cidrs(set, d, ext, mext, flags);
@@ -1107,8 +1101,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
1107 1101
1108 hsize = sizeof(*h); 1102 hsize = sizeof(*h);
1109#ifdef IP_SET_HASH_WITH_NETS 1103#ifdef IP_SET_HASH_WITH_NETS
1110 hsize += sizeof(struct net_prefixes) * 1104 hsize += sizeof(struct net_prefixes) * NLEN(set->family);
1111 (set->family == NFPROTO_IPV4 ? 32 : 128);
1112#endif 1105#endif
1113 h = kzalloc(hsize, GFP_KERNEL); 1106 h = kzalloc(hsize, GFP_KERNEL);
1114 if (!h) 1107 if (!h)
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index 35dd35873442..758b002130d9 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -115,6 +115,7 @@ iface_add(struct rb_root *root, const char **iface)
115#define IP_SET_HASH_WITH_NETS 115#define IP_SET_HASH_WITH_NETS
116#define IP_SET_HASH_WITH_RBTREE 116#define IP_SET_HASH_WITH_RBTREE
117#define IP_SET_HASH_WITH_MULTI 117#define IP_SET_HASH_WITH_MULTI
118#define IP_SET_HASH_WITH_NET0
118 119
119#define STREQ(a, b) (strcmp(a, b) == 0) 120#define STREQ(a, b) (strcmp(a, b) == 0)
120 121
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
index da00284b3571..ea8772afb6e7 100644
--- a/net/netfilter/ipset/ip_set_hash_netnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netnet.c
@@ -46,6 +46,7 @@ struct hash_netnet4_elem {
46 __be64 ipcmp; 46 __be64 ipcmp;
47 }; 47 };
48 u8 nomatch; 48 u8 nomatch;
49 u8 padding;
49 union { 50 union {
50 u8 cidr[2]; 51 u8 cidr[2];
51 u16 ccmp; 52 u16 ccmp;
@@ -271,6 +272,7 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
271struct hash_netnet6_elem { 272struct hash_netnet6_elem {
272 union nf_inet_addr ip[2]; 273 union nf_inet_addr ip[2];
273 u8 nomatch; 274 u8 nomatch;
275 u8 padding;
274 union { 276 union {
275 u8 cidr[2]; 277 u8 cidr[2];
276 u16 ccmp; 278 u16 ccmp;
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
index b8053d675fc3..bfaa94c7baa7 100644
--- a/net/netfilter/ipset/ip_set_hash_netportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
@@ -53,6 +53,7 @@ struct hash_netportnet4_elem {
53 u8 cidr[2]; 53 u8 cidr[2];
54 u16 ccmp; 54 u16 ccmp;
55 }; 55 };
56 u16 padding;
56 u8 nomatch:1; 57 u8 nomatch:1;
57 u8 proto; 58 u8 proto;
58}; 59};
@@ -324,6 +325,7 @@ struct hash_netportnet6_elem {
324 u8 cidr[2]; 325 u8 cidr[2];
325 u16 ccmp; 326 u16 ccmp;
326 }; 327 };
328 u16 padding;
327 u8 nomatch:1; 329 u8 nomatch:1;
328 u8 proto; 330 u8 proto;
329}; 331};
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 5016a6929085..a11674806707 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -824,22 +824,19 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
824 atomic_dec(&net->ct.count); 824 atomic_dec(&net->ct.count);
825 return ERR_PTR(-ENOMEM); 825 return ERR_PTR(-ENOMEM);
826 } 826 }
827 /*
828 * Let ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.next
829 * and ct->tuplehash[IP_CT_DIR_REPLY].hnnode.next unchanged.
830 */
831 memset(&ct->tuplehash[IP_CT_DIR_MAX], 0,
832 offsetof(struct nf_conn, proto) -
833 offsetof(struct nf_conn, tuplehash[IP_CT_DIR_MAX]));
834 spin_lock_init(&ct->lock); 827 spin_lock_init(&ct->lock);
835 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; 828 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
836 ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL; 829 ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL;
837 ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; 830 ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
838 /* save hash for reusing when confirming */ 831 /* save hash for reusing when confirming */
839 *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash; 832 *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash;
833 ct->status = 0;
840 /* Don't set timer yet: wait for confirmation */ 834 /* Don't set timer yet: wait for confirmation */
841 setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct); 835 setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
842 write_pnet(&ct->ct_net, net); 836 write_pnet(&ct->ct_net, net);
837 memset(&ct->__nfct_init_offset[0], 0,
838 offsetof(struct nf_conn, proto) -
839 offsetof(struct nf_conn, __nfct_init_offset[0]));
843#ifdef CONFIG_NF_CONNTRACK_ZONES 840#ifdef CONFIG_NF_CONNTRACK_ZONES
844 if (zone) { 841 if (zone) {
845 struct nf_conntrack_zone *nf_ct_zone; 842 struct nf_conntrack_zone *nf_ct_zone;
diff --git a/net/ipv4/netfilter/nf_nat_redirect_ipv4.c b/net/netfilter/nf_nat_redirect.c
index a220552fc532..97b75f9bfbcd 100644
--- a/net/ipv4/netfilter/nf_nat_redirect_ipv4.c
+++ b/net/netfilter/nf_nat_redirect.c
@@ -20,12 +20,13 @@
20#include <linux/netfilter.h> 20#include <linux/netfilter.h>
21#include <linux/types.h> 21#include <linux/types.h>
22#include <linux/netfilter_ipv4.h> 22#include <linux/netfilter_ipv4.h>
23#include <linux/netfilter_ipv6.h>
23#include <linux/netfilter/x_tables.h> 24#include <linux/netfilter/x_tables.h>
24#include <net/addrconf.h> 25#include <net/addrconf.h>
25#include <net/checksum.h> 26#include <net/checksum.h>
26#include <net/protocol.h> 27#include <net/protocol.h>
27#include <net/netfilter/nf_nat.h> 28#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/ipv4/nf_nat_redirect.h> 29#include <net/netfilter/nf_nat_redirect.h>
29 30
30unsigned int 31unsigned int
31nf_nat_redirect_ipv4(struct sk_buff *skb, 32nf_nat_redirect_ipv4(struct sk_buff *skb,
@@ -78,5 +79,49 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
78} 79}
79EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4); 80EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4);
80 81
82static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
83
84unsigned int
85nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
86 unsigned int hooknum)
87{
88 struct nf_nat_range newrange;
89 struct in6_addr newdst;
90 enum ip_conntrack_info ctinfo;
91 struct nf_conn *ct;
92
93 ct = nf_ct_get(skb, &ctinfo);
94 if (hooknum == NF_INET_LOCAL_OUT) {
95 newdst = loopback_addr;
96 } else {
97 struct inet6_dev *idev;
98 struct inet6_ifaddr *ifa;
99 bool addr = false;
100
101 rcu_read_lock();
102 idev = __in6_dev_get(skb->dev);
103 if (idev != NULL) {
104 list_for_each_entry(ifa, &idev->addr_list, if_list) {
105 newdst = ifa->addr;
106 addr = true;
107 break;
108 }
109 }
110 rcu_read_unlock();
111
112 if (!addr)
113 return NF_DROP;
114 }
115
116 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
117 newrange.min_addr.in6 = newdst;
118 newrange.max_addr.in6 = newdst;
119 newrange.min_proto = range->min_proto;
120 newrange.max_proto = range->max_proto;
121
122 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
123}
124EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6);
125
81MODULE_LICENSE("GPL"); 126MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 127MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/netfilter/xt_REDIRECT.c b/net/netfilter/xt_REDIRECT.c
index b6ec67efd900..03f0b370e178 100644
--- a/net/netfilter/xt_REDIRECT.c
+++ b/net/netfilter/xt_REDIRECT.c
@@ -26,8 +26,7 @@
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#include <net/netfilter/ipv4/nf_nat_redirect.h> 29#include <net/netfilter/nf_nat_redirect.h>
30#include <net/netfilter/ipv6/nf_nat_redirect.h>
31 30
32static unsigned int 31static unsigned int
33redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par) 32redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par)
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index a9faae89f955..30dbe34915ae 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -43,25 +43,29 @@ MODULE_LICENSE("GPL");
43MODULE_ALIAS("ipt_recent"); 43MODULE_ALIAS("ipt_recent");
44MODULE_ALIAS("ip6t_recent"); 44MODULE_ALIAS("ip6t_recent");
45 45
46static unsigned int ip_list_tot = 100; 46static unsigned int ip_list_tot __read_mostly = 100;
47static unsigned int ip_pkt_list_tot = 20; 47static unsigned int ip_list_hash_size __read_mostly;
48static unsigned int ip_list_hash_size = 0; 48static unsigned int ip_list_perms __read_mostly = 0644;
49static unsigned int ip_list_perms = 0644; 49static unsigned int ip_list_uid __read_mostly;
50static unsigned int ip_list_uid = 0; 50static unsigned int ip_list_gid __read_mostly;
51static unsigned int ip_list_gid = 0;
52module_param(ip_list_tot, uint, 0400); 51module_param(ip_list_tot, uint, 0400);
53module_param(ip_pkt_list_tot, uint, 0400);
54module_param(ip_list_hash_size, uint, 0400); 52module_param(ip_list_hash_size, uint, 0400);
55module_param(ip_list_perms, uint, 0400); 53module_param(ip_list_perms, uint, 0400);
56module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR); 54module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR);
57module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR); 55module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR);
58MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); 56MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
59MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
60MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); 57MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
61MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files"); 58MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files");
62MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files"); 59MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files");
63MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files"); 60MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files");
64 61
62/* retained for backwards compatibility */
63static unsigned int ip_pkt_list_tot __read_mostly;
64module_param(ip_pkt_list_tot, uint, 0400);
65MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
66
67#define XT_RECENT_MAX_NSTAMPS 256
68
65struct recent_entry { 69struct recent_entry {
66 struct list_head list; 70 struct list_head list;
67 struct list_head lru_list; 71 struct list_head lru_list;
@@ -79,6 +83,7 @@ struct recent_table {
79 union nf_inet_addr mask; 83 union nf_inet_addr mask;
80 unsigned int refcnt; 84 unsigned int refcnt;
81 unsigned int entries; 85 unsigned int entries;
86 u8 nstamps_max_mask;
82 struct list_head lru_list; 87 struct list_head lru_list;
83 struct list_head iphash[0]; 88 struct list_head iphash[0];
84}; 89};
@@ -90,7 +95,8 @@ struct recent_net {
90#endif 95#endif
91}; 96};
92 97
93static int recent_net_id; 98static int recent_net_id __read_mostly;
99
94static inline struct recent_net *recent_pernet(struct net *net) 100static inline struct recent_net *recent_pernet(struct net *net)
95{ 101{
96 return net_generic(net, recent_net_id); 102 return net_generic(net, recent_net_id);
@@ -171,12 +177,15 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
171 u_int16_t family, u_int8_t ttl) 177 u_int16_t family, u_int8_t ttl)
172{ 178{
173 struct recent_entry *e; 179 struct recent_entry *e;
180 unsigned int nstamps_max = t->nstamps_max_mask;
174 181
175 if (t->entries >= ip_list_tot) { 182 if (t->entries >= ip_list_tot) {
176 e = list_entry(t->lru_list.next, struct recent_entry, lru_list); 183 e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
177 recent_entry_remove(t, e); 184 recent_entry_remove(t, e);
178 } 185 }
179 e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot, 186
187 nstamps_max += 1;
188 e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * nstamps_max,
180 GFP_ATOMIC); 189 GFP_ATOMIC);
181 if (e == NULL) 190 if (e == NULL)
182 return NULL; 191 return NULL;
@@ -197,7 +206,7 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
197 206
198static void recent_entry_update(struct recent_table *t, struct recent_entry *e) 207static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
199{ 208{
200 e->index %= ip_pkt_list_tot; 209 e->index &= t->nstamps_max_mask;
201 e->stamps[e->index++] = jiffies; 210 e->stamps[e->index++] = jiffies;
202 if (e->index > e->nstamps) 211 if (e->index > e->nstamps)
203 e->nstamps = e->index; 212 e->nstamps = e->index;
@@ -326,6 +335,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
326 kuid_t uid; 335 kuid_t uid;
327 kgid_t gid; 336 kgid_t gid;
328#endif 337#endif
338 unsigned int nstamp_mask;
329 unsigned int i; 339 unsigned int i;
330 int ret = -EINVAL; 340 int ret = -EINVAL;
331 size_t sz; 341 size_t sz;
@@ -349,19 +359,33 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
349 return -EINVAL; 359 return -EINVAL;
350 if ((info->check_set & XT_RECENT_REAP) && !info->seconds) 360 if ((info->check_set & XT_RECENT_REAP) && !info->seconds)
351 return -EINVAL; 361 return -EINVAL;
352 if (info->hit_count > ip_pkt_list_tot) { 362 if (info->hit_count >= XT_RECENT_MAX_NSTAMPS) {
353 pr_info("hitcount (%u) is larger than " 363 pr_info("hitcount (%u) is larger than allowed maximum (%u)\n",
354 "packets to be remembered (%u)\n", 364 info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
355 info->hit_count, ip_pkt_list_tot);
356 return -EINVAL; 365 return -EINVAL;
357 } 366 }
358 if (info->name[0] == '\0' || 367 if (info->name[0] == '\0' ||
359 strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) 368 strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
360 return -EINVAL; 369 return -EINVAL;
361 370
371 if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot)
372 nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1;
373 else if (info->hit_count)
374 nstamp_mask = roundup_pow_of_two(info->hit_count) - 1;
375 else
376 nstamp_mask = 32 - 1;
377
362 mutex_lock(&recent_mutex); 378 mutex_lock(&recent_mutex);
363 t = recent_table_lookup(recent_net, info->name); 379 t = recent_table_lookup(recent_net, info->name);
364 if (t != NULL) { 380 if (t != NULL) {
381 if (info->hit_count > t->nstamps_max_mask) {
382 pr_info("hitcount (%u) is larger than packets to be remembered (%u) for table %s\n",
383 info->hit_count, t->nstamps_max_mask + 1,
384 info->name);
385 ret = -EINVAL;
386 goto out;
387 }
388
365 t->refcnt++; 389 t->refcnt++;
366 ret = 0; 390 ret = 0;
367 goto out; 391 goto out;
@@ -377,6 +401,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
377 goto out; 401 goto out;
378 } 402 }
379 t->refcnt = 1; 403 t->refcnt = 1;
404 t->nstamps_max_mask = nstamp_mask;
380 405
381 memcpy(&t->mask, &info->mask, sizeof(t->mask)); 406 memcpy(&t->mask, &info->mask, sizeof(t->mask));
382 strcpy(t->name, info->name); 407 strcpy(t->name, info->name);
@@ -497,9 +522,12 @@ static void recent_seq_stop(struct seq_file *s, void *v)
497static int recent_seq_show(struct seq_file *seq, void *v) 522static int recent_seq_show(struct seq_file *seq, void *v)
498{ 523{
499 const struct recent_entry *e = v; 524 const struct recent_entry *e = v;
525 struct recent_iter_state *st = seq->private;
526 const struct recent_table *t = st->table;
500 unsigned int i; 527 unsigned int i;
501 528
502 i = (e->index - 1) % ip_pkt_list_tot; 529 i = (e->index - 1) & t->nstamps_max_mask;
530
503 if (e->family == NFPROTO_IPV4) 531 if (e->family == NFPROTO_IPV4)
504 seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u", 532 seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u",
505 &e->addr.ip, e->ttl, e->stamps[i], e->index); 533 &e->addr.ip, e->ttl, e->stamps[i], e->index);
@@ -717,7 +745,9 @@ static int __init recent_mt_init(void)
717{ 745{
718 int err; 746 int err;
719 747
720 if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255) 748 BUILD_BUG_ON_NOT_POWER_OF_2(XT_RECENT_MAX_NSTAMPS);
749
750 if (!ip_list_tot || ip_pkt_list_tot >= XT_RECENT_MAX_NSTAMPS)
721 return -EINVAL; 751 return -EINVAL;
722 ip_list_hash_size = 1 << fls(ip_list_tot); 752 ip_list_hash_size = 1 << fls(ip_list_tot);
723 753
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
index 5732cd64acc0..0d47afea9682 100644
--- a/net/netfilter/xt_set.c
+++ b/net/netfilter/xt_set.c
@@ -157,7 +157,7 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par)
157/* Revision 3 match */ 157/* Revision 3 match */
158 158
159static bool 159static bool
160match_counter(u64 counter, const struct ip_set_counter_match *info) 160match_counter0(u64 counter, const struct ip_set_counter_match0 *info)
161{ 161{
162 switch (info->op) { 162 switch (info->op) {
163 case IPSET_COUNTER_NONE: 163 case IPSET_COUNTER_NONE:
@@ -192,14 +192,60 @@ set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
192 if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) 192 if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
193 return ret; 193 return ret;
194 194
195 if (!match_counter(opt.ext.packets, &info->packets)) 195 if (!match_counter0(opt.ext.packets, &info->packets))
196 return 0; 196 return 0;
197 return match_counter(opt.ext.bytes, &info->bytes); 197 return match_counter0(opt.ext.bytes, &info->bytes);
198} 198}
199 199
200#define set_match_v3_checkentry set_match_v1_checkentry 200#define set_match_v3_checkentry set_match_v1_checkentry
201#define set_match_v3_destroy set_match_v1_destroy 201#define set_match_v3_destroy set_match_v1_destroy
202 202
203/* Revision 4 match */
204
205static bool
206match_counter(u64 counter, const struct ip_set_counter_match *info)
207{
208 switch (info->op) {
209 case IPSET_COUNTER_NONE:
210 return true;
211 case IPSET_COUNTER_EQ:
212 return counter == info->value;
213 case IPSET_COUNTER_NE:
214 return counter != info->value;
215 case IPSET_COUNTER_LT:
216 return counter < info->value;
217 case IPSET_COUNTER_GT:
218 return counter > info->value;
219 }
220 return false;
221}
222
223static bool
224set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
225{
226 const struct xt_set_info_match_v4 *info = par->matchinfo;
227 ADT_OPT(opt, par->family, info->match_set.dim,
228 info->match_set.flags, info->flags, UINT_MAX);
229 int ret;
230
231 if (info->packets.op != IPSET_COUNTER_NONE ||
232 info->bytes.op != IPSET_COUNTER_NONE)
233 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
234
235 ret = match_set(info->match_set.index, skb, par, &opt,
236 info->match_set.flags & IPSET_INV_MATCH);
237
238 if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
239 return ret;
240
241 if (!match_counter(opt.ext.packets, &info->packets))
242 return 0;
243 return match_counter(opt.ext.bytes, &info->bytes);
244}
245
246#define set_match_v4_checkentry set_match_v1_checkentry
247#define set_match_v4_destroy set_match_v1_destroy
248
203/* Revision 0 interface: backward compatible with netfilter/iptables */ 249/* Revision 0 interface: backward compatible with netfilter/iptables */
204 250
205static unsigned int 251static unsigned int
@@ -573,6 +619,27 @@ static struct xt_match set_matches[] __read_mostly = {
573 .destroy = set_match_v3_destroy, 619 .destroy = set_match_v3_destroy,
574 .me = THIS_MODULE 620 .me = THIS_MODULE
575 }, 621 },
622 /* new revision for counters support: update, match */
623 {
624 .name = "set",
625 .family = NFPROTO_IPV4,
626 .revision = 4,
627 .match = set_match_v4,
628 .matchsize = sizeof(struct xt_set_info_match_v4),
629 .checkentry = set_match_v4_checkentry,
630 .destroy = set_match_v4_destroy,
631 .me = THIS_MODULE
632 },
633 {
634 .name = "set",
635 .family = NFPROTO_IPV6,
636 .revision = 4,
637 .match = set_match_v4,
638 .matchsize = sizeof(struct xt_set_info_match_v4),
639 .checkentry = set_match_v4_checkentry,
640 .destroy = set_match_v4_destroy,
641 .me = THIS_MODULE
642 },
576}; 643};
577 644
578static struct xt_target set_targets[] __read_mostly = { 645static struct xt_target set_targets[] __read_mostly = {