aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-11-16 12:42:43 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-16 12:42:43 -0500
commit545b29019c8959c805abfe8194d47e989f1a6e5f (patch)
tree120f88abf0b4b2317072579c667fddfccb930fe5
parent130cd273d4a46a3011b1cc739f5d2af78779d666 (diff)
parentd3976a53ce1f4763cb910d047e8763e4c696e5f7 (diff)
Merge branch 'master' of git://1984.lsi.us.es/nf-next
Conflicts: net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c Minor conflict due to some IS_ENABLED conversions done in net-next. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/in6.h1
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6_tables.h3
-rw-r--r--net/ipv4/netfilter/iptable_nat.c4
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c4
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c66
-rw-r--r--net/netfilter/ipvs/ip_vs_nfct.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c8
7 files changed, 77 insertions, 11 deletions
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 1e3159989958..f79c3721da6e 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -240,6 +240,7 @@ struct in6_flowlabel_req {
240 * 240 *
241 * IP6T_SO_GET_REVISION_MATCH 68 241 * IP6T_SO_GET_REVISION_MATCH 68
242 * IP6T_SO_GET_REVISION_TARGET 69 242 * IP6T_SO_GET_REVISION_TARGET 69
243 * IP6T_SO_ORIGINAL_DST 80
243 */ 244 */
244 245
245/* RFC5014: Source address selection */ 246/* RFC5014: Source address selection */
diff --git a/include/uapi/linux/netfilter_ipv6/ip6_tables.h b/include/uapi/linux/netfilter_ipv6/ip6_tables.h
index bf1ef65cc582..649c68062dca 100644
--- a/include/uapi/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6_tables.h
@@ -178,6 +178,9 @@ struct ip6t_error {
178#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5) 178#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
179#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET 179#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
180 180
181/* obtain original address if REDIRECT'd connection */
182#define IP6T_SO_ORIGINAL_DST 80
183
181/* ICMP matching stuff */ 184/* ICMP matching stuff */
182struct ip6t_icmp { 185struct ip6t_icmp {
183 __u8 type; /* type to match */ 186 __u8 type; /* type to match */
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index a82047282dbb..ac635a7b4416 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -276,9 +276,7 @@ static int __net_init iptable_nat_net_init(struct net *net)
276 return -ENOMEM; 276 return -ENOMEM;
277 net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl); 277 net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
278 kfree(repl); 278 kfree(repl);
279 if (IS_ERR(net->ipv4.nat_table)) 279 return PTR_RET(net->ipv4.nat_table);
280 return PTR_ERR(net->ipv4.nat_table);
281 return 0;
282} 280}
283 281
284static void __net_exit iptable_nat_net_exit(struct net *net) 282static void __net_exit iptable_nat_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index d57dab17a182..fa84cf8ec6bc 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -277,9 +277,7 @@ static int __net_init ip6table_nat_net_init(struct net *net)
277 return -ENOMEM; 277 return -ENOMEM;
278 net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); 278 net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
279 kfree(repl); 279 kfree(repl);
280 if (IS_ERR(net->ipv6.ip6table_nat)) 280 return PTR_RET(net->ipv6.ip6table_nat);
281 return PTR_ERR(net->ipv6.ip6table_nat);
282 return 0;
283} 281}
284 282
285static void __net_exit ip6table_nat_net_exit(struct net *net) 283static void __net_exit ip6table_nat_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index ccb5cbe93549..00ee17c3e893 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -21,6 +21,7 @@
21 21
22#include <linux/netfilter_bridge.h> 22#include <linux/netfilter_bridge.h>
23#include <linux/netfilter_ipv6.h> 23#include <linux/netfilter_ipv6.h>
24#include <linux/netfilter_ipv6/ip6_tables.h>
24#include <net/netfilter/nf_conntrack.h> 25#include <net/netfilter/nf_conntrack.h>
25#include <net/netfilter/nf_conntrack_helper.h> 26#include <net/netfilter/nf_conntrack_helper.h>
26#include <net/netfilter/nf_conntrack_l4proto.h> 27#include <net/netfilter/nf_conntrack_l4proto.h>
@@ -295,6 +296,55 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
295 }, 296 },
296}; 297};
297 298
299static int
300ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
301{
302 const struct inet_sock *inet = inet_sk(sk);
303 const struct ipv6_pinfo *inet6 = inet6_sk(sk);
304 const struct nf_conntrack_tuple_hash *h;
305 struct sockaddr_in6 sin6;
306 struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
307 struct nf_conn *ct;
308
309 tuple.src.u3.in6 = inet6->rcv_saddr;
310 tuple.src.u.tcp.port = inet->inet_sport;
311 tuple.dst.u3.in6 = inet6->daddr;
312 tuple.dst.u.tcp.port = inet->inet_dport;
313 tuple.dst.protonum = sk->sk_protocol;
314
315 if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
316 return -ENOPROTOOPT;
317
318 if (*len < 0 || (unsigned int) *len < sizeof(sin6))
319 return -EINVAL;
320
321 h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple);
322 if (!h) {
323 pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
324 &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
325 &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
326 return -ENOENT;
327 }
328
329 ct = nf_ct_tuplehash_to_ctrack(h);
330
331 sin6.sin6_family = AF_INET6;
332 sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
333 sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
334 memcpy(&sin6.sin6_addr,
335 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
336 sizeof(sin6.sin6_addr));
337
338 nf_ct_put(ct);
339
340 if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
341 sin6.sin6_scope_id = sk->sk_bound_dev_if;
342 else
343 sin6.sin6_scope_id = 0;
344
345 return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
346}
347
298#if IS_ENABLED(CONFIG_NF_CT_NETLINK) 348#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
299 349
300#include <linux/netfilter/nfnetlink.h> 350#include <linux/netfilter/nfnetlink.h>
@@ -359,6 +409,14 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
359MODULE_LICENSE("GPL"); 409MODULE_LICENSE("GPL");
360MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); 410MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
361 411
412static struct nf_sockopt_ops so_getorigdst6 = {
413 .pf = NFPROTO_IPV6,
414 .get_optmin = IP6T_SO_ORIGINAL_DST,
415 .get_optmax = IP6T_SO_ORIGINAL_DST + 1,
416 .get = ipv6_getorigdst,
417 .owner = THIS_MODULE,
418};
419
362static int ipv6_net_init(struct net *net) 420static int ipv6_net_init(struct net *net)
363{ 421{
364 int ret = 0; 422 int ret = 0;
@@ -425,6 +483,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
425 need_conntrack(); 483 need_conntrack();
426 nf_defrag_ipv6_enable(); 484 nf_defrag_ipv6_enable();
427 485
486 ret = nf_register_sockopt(&so_getorigdst6);
487 if (ret < 0) {
488 pr_err("Unable to register netfilter socket option\n");
489 return ret;
490 }
491
428 ret = register_pernet_subsys(&ipv6_net_ops); 492 ret = register_pernet_subsys(&ipv6_net_ops);
429 if (ret < 0) 493 if (ret < 0)
430 goto cleanup_pernet; 494 goto cleanup_pernet;
@@ -440,6 +504,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
440 cleanup_ipv6: 504 cleanup_ipv6:
441 unregister_pernet_subsys(&ipv6_net_ops); 505 unregister_pernet_subsys(&ipv6_net_ops);
442 cleanup_pernet: 506 cleanup_pernet:
507 nf_unregister_sockopt(&so_getorigdst6);
443 return ret; 508 return ret;
444} 509}
445 510
@@ -448,6 +513,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void)
448 synchronize_net(); 513 synchronize_net();
449 nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); 514 nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
450 unregister_pernet_subsys(&ipv6_net_ops); 515 unregister_pernet_subsys(&ipv6_net_ops);
516 nf_unregister_sockopt(&so_getorigdst6);
451} 517}
452 518
453module_init(nf_conntrack_l3proto_ipv6_init); 519module_init(nf_conntrack_l3proto_ipv6_init);
diff --git a/net/netfilter/ipvs/ip_vs_nfct.c b/net/netfilter/ipvs/ip_vs_nfct.c
index 022e77e1e766..c8beafd401aa 100644
--- a/net/netfilter/ipvs/ip_vs_nfct.c
+++ b/net/netfilter/ipvs/ip_vs_nfct.c
@@ -82,7 +82,7 @@ void
82ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin) 82ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin)
83{ 83{
84 enum ip_conntrack_info ctinfo; 84 enum ip_conntrack_info ctinfo;
85 struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); 85 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
86 struct nf_conntrack_tuple new_tuple; 86 struct nf_conntrack_tuple new_tuple;
87 87
88 if (ct == NULL || nf_ct_is_confirmed(ct) || nf_ct_is_untracked(ct) || 88 if (ct == NULL || nf_ct_is_confirmed(ct) || nf_ct_is_untracked(ct) ||
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 12008b47e5ca..ee6b7a9f1ec2 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -594,7 +594,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
594#if IS_ENABLED(CONFIG_NF_CONNTRACK) 594#if IS_ENABLED(CONFIG_NF_CONNTRACK)
595 if (cp->flags & IP_VS_CONN_F_SYNC && local) { 595 if (cp->flags & IP_VS_CONN_F_SYNC && local) {
596 enum ip_conntrack_info ctinfo; 596 enum ip_conntrack_info ctinfo;
597 struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); 597 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
598 598
599 if (ct && !nf_ct_is_untracked(ct)) { 599 if (ct && !nf_ct_is_untracked(ct)) {
600 IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0, 600 IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0,
@@ -710,7 +710,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
710#if IS_ENABLED(CONFIG_NF_CONNTRACK) 710#if IS_ENABLED(CONFIG_NF_CONNTRACK)
711 if (cp->flags & IP_VS_CONN_F_SYNC && local) { 711 if (cp->flags & IP_VS_CONN_F_SYNC && local) {
712 enum ip_conntrack_info ctinfo; 712 enum ip_conntrack_info ctinfo;
713 struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); 713 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
714 714
715 if (ct && !nf_ct_is_untracked(ct)) { 715 if (ct && !nf_ct_is_untracked(ct)) {
716 IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0, 716 IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
@@ -1235,7 +1235,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
1235#if IS_ENABLED(CONFIG_NF_CONNTRACK) 1235#if IS_ENABLED(CONFIG_NF_CONNTRACK)
1236 if (cp->flags & IP_VS_CONN_F_SYNC && local) { 1236 if (cp->flags & IP_VS_CONN_F_SYNC && local) {
1237 enum ip_conntrack_info ctinfo; 1237 enum ip_conntrack_info ctinfo;
1238 struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); 1238 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
1239 1239
1240 if (ct && !nf_ct_is_untracked(ct)) { 1240 if (ct && !nf_ct_is_untracked(ct)) {
1241 IP_VS_DBG(10, "%s(): " 1241 IP_VS_DBG(10, "%s(): "
@@ -1356,7 +1356,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1356#if IS_ENABLED(CONFIG_NF_CONNTRACK) 1356#if IS_ENABLED(CONFIG_NF_CONNTRACK)
1357 if (cp->flags & IP_VS_CONN_F_SYNC && local) { 1357 if (cp->flags & IP_VS_CONN_F_SYNC && local) {
1358 enum ip_conntrack_info ctinfo; 1358 enum ip_conntrack_info ctinfo;
1359 struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); 1359 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
1360 1360
1361 if (ct && !nf_ct_is_untracked(ct)) { 1361 if (ct && !nf_ct_is_untracked(ct)) {
1362 IP_VS_DBG(10, "%s(): " 1362 IP_VS_DBG(10, "%s(): "