Currenly, this parameter can be configured via sysctl only. But sysctl is considered as depricated interface (man 2 sysctl), and it only can applied to current's net namespace (this requires to do setns() to change it in not current's net ns).
So, let's export the parameter to /proc in standard way, and this allows to access another process namespace via /proc/[pid]/net/ip6_nonlocal_bind. Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> --- net/ipv6/proc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 6e57028d2e91..2d0aa59c2d0d 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -312,6 +312,47 @@ int snmp6_unregister_dev(struct inet6_dev *idev) return 0; } +static int nonlocal_bind_show(struct seq_file *seq, void *v) +{ + struct net *net = seq->private; + + seq_printf(seq, "%d\n", !!net->ipv6.sysctl.ip_nonlocal_bind); + return 0; +} + +static int open_nonlocal_bind(struct inode *inode, struct file *file) +{ + return single_open_net(inode, file, nonlocal_bind_show); +} + +static ssize_t write_nonlocal_bind(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct net *net = ((struct seq_file *)file->private_data)->private; + char buf[3]; + + if (*ppos || count <= 0 || count > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, ubuf, count)) + return -EFAULT; + buf[0] -= '0'; + if ((count == 3 && buf[2] != '\0') || + (count >= 2 && buf[1] != '\n') || + (buf[0] != 0 && buf[0] != 1)) + return -EINVAL; + + net->ipv6.sysctl.ip_nonlocal_bind = buf[0]; + return count; +} + +static const struct file_operations nonlocal_bind_ops = { + .open = open_nonlocal_bind, + .read = seq_read, + .write = write_nonlocal_bind, + .release = single_release_net, +}; + static int __net_init ipv6_proc_init_net(struct net *net) { if (!proc_create("sockstat6", 0444, net->proc_net, @@ -321,12 +362,18 @@ static int __net_init ipv6_proc_init_net(struct net *net) if (!proc_create("snmp6", 0444, net->proc_net, &snmp6_seq_fops)) goto proc_snmp6_fail; + if (!proc_create_data("ip6_nonlocal_bind", 0644, + net->proc_net, &nonlocal_bind_ops, net)) + goto proc_bind_fail; + net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net); if (!net->mib.proc_net_devsnmp6) goto proc_dev_snmp6_fail; return 0; proc_dev_snmp6_fail: + remove_proc_entry("ip6_nonlocal_bind", net->proc_net); +proc_bind_fail: remove_proc_entry("snmp6", net->proc_net); proc_snmp6_fail: remove_proc_entry("sockstat6", net->proc_net); @@ -337,6 +384,7 @@ static void __net_exit ipv6_proc_exit_net(struct net *net) { remove_proc_entry("sockstat6", net->proc_net); remove_proc_entry("dev_snmp6", net->proc_net); + remove_proc_entry("ip6_nonlocal_bind", net->proc_net); remove_proc_entry("snmp6", net->proc_net); }