From 44934986d09b6bd55023123b236e09db7a03778a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timh=20Bergstr=C3=B6m?= <timh@shiwebs.net>
Date: Tue, 25 Jun 2013 12:43:00 +0200
Subject: [PATCH] UBUNTU: SAUCE: Added ip_nonlocal_bind functionality for IPv6
Signed-off-by: timh <timh@shiwebs.net>
* Added sysctl for ipv6 equalivient of net.ipv4.ip_nonlocal_bind.
* Added check in inet6_bind() for ip6_nonlocal_bind so we allow
binding to arbitrary IPv6 addresses on a host.
Same weaknesses and strengths that exists for ip_nonlocal_bind apply
on ip6_nonlocal_bind.
---
include/linux/sysctl.h | 1 +
include/net/ipv6.h | 2 ++
include/net/netns/ipv6.h | 1 +
kernel/sysctl_binary.c | 1 +
net/ipv6/af_inet6.c | 9 +++++++--
net/ipv6/sysctl_net_ipv6.c | 7 +++++++
6 files changed, 19 insertions(+), 2 deletions(-)
@@ -528,6 +528,7 @@ enum {
NET_IPV6_IP6FRAG_TIME=23,
NET_IPV6_IP6FRAG_SECRET_INTERVAL=24,
NET_IPV6_MLD_MAX_MSF=25,
+ NET_IPV6_NONLOCAL_BIND=30,
};
enum {
@@ -583,6 +583,8 @@ extern struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
* socket options (ipv6_sockglue.c)
*/
+extern int sysctl_ip6_nonlocal_bind;
+
extern int ipv6_setsockopt(struct sock *sk, int level,
int optname,
char __user *optval,
@@ -18,6 +18,7 @@ struct netns_sysctl_ipv6 {
struct ctl_table_header *frags_hdr;
#endif
int bindv6only;
+ int ip6_nonlocal_bind;
int flush_delay;
int ip6_rt_max_size;
int ip6_rt_gc_min_interval;
@@ -558,6 +558,7 @@ static const struct bin_table bin_net_ipv6_table[] = {
{ CTL_DIR, NET_IPV6_ROUTE, "route", bin_net_ipv6_route_table },
{ CTL_DIR, NET_IPV6_ICMP, "icmp", bin_net_ipv6_icmp_table },
{ CTL_INT, NET_IPV6_BINDV6ONLY, "bindv6only" },
+ { CTL_INT, NET_IPV6_NONLOCAL_BIND, "ip6_nonlocal_bind" },
{ CTL_INT, NET_IPV6_IP6FRAG_HIGH_THRESH, "ip6frag_high_thresh" },
{ CTL_INT, NET_IPV6_IP6FRAG_LOW_THRESH, "ip6frag_low_thresh" },
{ CTL_INT, NET_IPV6_IP6FRAG_TIME, "ip6frag_time" },
@@ -255,6 +255,9 @@ out_rcu_unlock:
/* bind for INET6 API */
+int sysctl_ip6_nonlocal_bind __read_mostly;
+EXPORT_SYMBOL(sysctl_ip6_nonlocal_bind);
+
int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr;
@@ -308,7 +311,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Reproduce AF_INET checks to make the bindings consistent */
v4addr = addr->sin6_addr.s6_addr32[3];
chk_addr_ret = inet_addr_type(net, v4addr);
- if (!sysctl_ip_nonlocal_bind &&
+ if (!sysctl_ip6_nonlocal_bind &&
!(inet->freebind || inet->transparent) &&
v4addr != htonl(INADDR_ANY) &&
chk_addr_ret != RTN_LOCAL &&
@@ -348,7 +351,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
- if (!(inet->freebind || inet->transparent) &&
+ if (!sysctl_ip6_nonlocal_bind &&
+ !(inet->freebind || inet->transparent) &&
!ipv6_chk_addr(net, &addr->sin6_addr,
dev, 0)) {
err = -EADDRNOTAVAIL;
@@ -1008,6 +1012,7 @@ static int __net_init inet6_net_init(struct net *net)
int err = 0;
net->ipv6.sysctl.bindv6only = 0;
+ net->ipv6.sysctl.ip6_nonlocal_bind = 0;
net->ipv6.sysctl.icmpv6_time = 1*HZ;
err = ipv6_init_mibs(net);
@@ -24,6 +24,13 @@ static ctl_table ipv6_table_template[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "ip6_nonlocal_bind",
+ .data = &sysctl_ip6_nonlocal_bind,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
{ }
};
--
1.7.9.5