ipv6: allow nonlocal_bind for ipv6 addresses
Luis Henriques
luis.henriques at canonical.com
Wed Jun 26 16:53:05 UTC 2013
Hi,
"Timh B" <timh at shiwebs.net> writes:
> Hi,
>
> We've encountered a problem when migrating services that uses vrrpd (for
> example) to IPv6 (dualstack), a nonlocal_bind problem to be exact, for
> IPv4 there's a sysctl-setting that allows us to bind to addresses that are
> not configured on the host directly.
>
> I'm aware that there's freebind and ip_transparent options to setsockopt()
> but changing all the services's code would have been a larger task than
> implementing the nonlocal_bind option for IPv6 in the kenrel.
>
> The patch is done for kernel 3.5, so for 3.2 (Ubuntu 12.04 LTS) the patch
> from Maciej Żenczykowski has to be applied first;
>
> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/net/ipv6/af_inet6.c?id=f74024d9f05caa570dcf7582b498bbf011943491
>
> My patch is attached.
Although I can't assess the correctness of your patch, this is the
kind of changes I don't feel comfortable to see in the Ubuntu kernels
without being in mainline kernel.
>From your description, this is an upstream problem so I think you
should try to submit it to lkml (and netdev, I guess), possibly
tagging it for inclusion in stable kernels as well.
Cheers,
--
Luis
>
> Usage: sysctl -w net.ipv6.ip6_nonlocal_bind=1
>
> -- Timh
>
> From 44934986d09b6bd55023123b236e09db7a03778a Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Timh=20Bergstr=C3=B6m?= <timh at 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 at 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(-)
>
> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index c34b4c8..7af300f 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -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 {
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index c11fa5d..44fdad6 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -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,
> diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
> index b42be53..cfc9486 100644
> --- a/include/net/netns/ipv6.h
> +++ b/include/net/netns/ipv6.h
> @@ -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;
> diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
> index 9f9aa32..b611831 100644
> --- a/kernel/sysctl_binary.c
> +++ b/kernel/sysctl_binary.c
> @@ -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" },
> diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> index e22e6d8..55dd5be 100644
> --- a/net/ipv6/af_inet6.c
> +++ b/net/ipv6/af_inet6.c
> @@ -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);
> diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
> index e85c48b..87699ca 100644
> --- a/net/ipv6/sysctl_net_ipv6.c
> +++ b/net/ipv6/sysctl_net_ipv6.c
> @@ -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
More information about the kernel-team
mailing list