2019-05-27 06:55:01 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* IPv6 BSD socket options interface
|
2007-02-09 14:24:49 +00:00
|
|
|
* Linux INET6 implementation
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
2007-02-09 14:24:49 +00:00
|
|
|
* Pedro Roque <roque@di.fc.ul.pt>
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Based on linux/net/ipv4/ip_sockglue.c
|
|
|
|
*
|
|
|
|
* FIXME: Make the setsockopt code POSIX compliant: That is
|
|
|
|
*
|
|
|
|
* o Truncate getsockopt returns
|
|
|
|
* o Return an optlen of the truncated length if need be
|
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* David L Stevens <dlstevens@us.ibm.com>:
|
|
|
|
* - added multicast source filtering API for MLDv2
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
2006-01-11 20:17:47 +00:00
|
|
|
#include <linux/capability.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/sockios.h>
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/in6.h>
|
2008-04-03 00:22:53 +00:00
|
|
|
#include <linux/mroute6.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
#include <linux/netfilter.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/snmp.h>
|
|
|
|
#include <net/ipv6.h>
|
|
|
|
#include <net/ndisc.h>
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <net/transp_v6.h>
|
|
|
|
#include <net/ip6_route.h>
|
|
|
|
#include <net/addrconf.h>
|
|
|
|
#include <net/inet_common.h>
|
|
|
|
#include <net/tcp.h>
|
|
|
|
#include <net/udp.h>
|
2006-11-27 19:10:57 +00:00
|
|
|
#include <net/udplite.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <net/xfrm.h>
|
2008-04-27 08:06:07 +00:00
|
|
|
#include <net/compat.h>
|
2016-11-08 13:59:21 +00:00
|
|
|
#include <net/seg6.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2016-12-24 19:46:01 +00:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
struct ip6_ra_chain *ip6_ra_chain;
|
|
|
|
DEFINE_RWLOCK(ip6_ra_lock);
|
|
|
|
|
2008-07-19 07:28:58 +00:00
|
|
|
int ip6_ra_control(struct sock *sk, int sel)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ip6_ra_chain *ra, *new_ra, **rap;
|
|
|
|
|
|
|
|
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
|
2009-10-15 06:30:45 +00:00
|
|
|
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
|
2008-06-11 18:27:26 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-08-24 20:53:10 +00:00
|
|
|
new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
|
2019-05-24 03:19:46 +00:00
|
|
|
if (sel >= 0 && !new_ra)
|
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
write_lock_bh(&ip6_ra_lock);
|
2014-08-24 20:53:10 +00:00
|
|
|
for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (ra->sk == sk) {
|
2014-08-24 20:53:10 +00:00
|
|
|
if (sel >= 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
2005-11-08 17:41:34 +00:00
|
|
|
kfree(new_ra);
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EADDRINUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rap = ra->next;
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
|
|
|
|
sock_put(sk);
|
|
|
|
kfree(ra);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2015-03-29 13:00:04 +00:00
|
|
|
if (!new_ra) {
|
2005-04-16 22:20:36 +00:00
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
new_ra->sk = sk;
|
|
|
|
new_ra->sel = sel;
|
|
|
|
new_ra->next = ra;
|
|
|
|
*rap = new_ra;
|
|
|
|
sock_hold(sk);
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-14 06:21:52 +00:00
|
|
|
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
|
|
|
struct ipv6_txoptions *opt)
|
|
|
|
{
|
|
|
|
if (inet_sk(sk)->is_icsk) {
|
|
|
|
if (opt &&
|
|
|
|
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
|
2009-10-15 06:30:45 +00:00
|
|
|
inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
|
2008-04-14 06:21:52 +00:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
|
|
|
|
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
|
|
|
}
|
|
|
|
}
|
2015-11-30 03:37:57 +00:00
|
|
|
opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
|
|
|
|
opt);
|
2008-04-14 06:21:52 +00:00
|
|
|
sk_dst_reset(sk);
|
|
|
|
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2015-03-18 17:50:42 +00:00
|
|
|
static bool setsockopt_needs_rtnl(int optname)
|
|
|
|
{
|
|
|
|
switch (optname) {
|
2016-10-20 06:35:12 +00:00
|
|
|
case IPV6_ADDRFORM:
|
2015-03-18 17:50:42 +00:00
|
|
|
case IPV6_ADD_MEMBERSHIP:
|
|
|
|
case IPV6_DROP_MEMBERSHIP:
|
2015-03-20 14:37:17 +00:00
|
|
|
case IPV6_JOIN_ANYCAST:
|
|
|
|
case IPV6_LEAVE_ANYCAST:
|
2015-03-18 17:50:42 +00:00
|
|
|
case MCAST_JOIN_GROUP:
|
|
|
|
case MCAST_LEAVE_GROUP:
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-18 17:50:43 +00:00
|
|
|
case MCAST_JOIN_SOURCE_GROUP:
|
|
|
|
case MCAST_LEAVE_SOURCE_GROUP:
|
|
|
|
case MCAST_BLOCK_SOURCE:
|
|
|
|
case MCAST_UNBLOCK_SOURCE:
|
|
|
|
case MCAST_MSFILTER:
|
2015-03-18 17:50:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
static int copy_group_source_from_sockptr(struct group_source_req *greqs,
|
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 06:23:30 +00:00
|
|
|
{
|
|
|
|
if (in_compat_syscall()) {
|
|
|
|
struct compat_group_source_req gr32;
|
|
|
|
|
|
|
|
if (optlen < sizeof(gr32))
|
|
|
|
return -EINVAL;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
|
2020-07-17 06:23:30 +00:00
|
|
|
return -EFAULT;
|
|
|
|
greqs->gsr_interface = gr32.gsr_interface;
|
|
|
|
greqs->gsr_group = gr32.gsr_group;
|
|
|
|
greqs->gsr_source = gr32.gsr_source;
|
|
|
|
} else {
|
|
|
|
if (optlen < sizeof(*greqs))
|
|
|
|
return -EINVAL;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
|
2020-07-17 06:23:30 +00:00
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-27 15:00:01 +00:00
|
|
|
static int do_ipv6_mcast_group_source(struct sock *sk, int optname,
|
2020-07-23 06:09:03 +00:00
|
|
|
sockptr_t optval, int optlen)
|
2020-04-27 15:00:01 +00:00
|
|
|
{
|
2020-07-17 06:23:30 +00:00
|
|
|
struct group_source_req greqs;
|
2020-04-27 15:00:01 +00:00
|
|
|
int omode, add;
|
2020-07-17 06:23:30 +00:00
|
|
|
int ret;
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
ret = copy_group_source_from_sockptr(&greqs, optval, optlen);
|
2020-07-17 06:23:30 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2020-04-27 15:00:01 +00:00
|
|
|
|
2020-07-17 06:23:30 +00:00
|
|
|
if (greqs.gsr_group.ss_family != AF_INET6 ||
|
|
|
|
greqs.gsr_source.ss_family != AF_INET6)
|
2020-04-27 15:00:01 +00:00
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
if (optname == MCAST_BLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 1;
|
|
|
|
} else if (optname == MCAST_UNBLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 0;
|
|
|
|
} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
int retv;
|
|
|
|
|
2020-07-17 06:23:30 +00:00
|
|
|
psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
|
|
|
|
retv = ipv6_sock_mc_join_ssm(sk, greqs.gsr_interface,
|
2020-04-27 15:00:01 +00:00
|
|
|
&psin6->sin6_addr,
|
|
|
|
MCAST_INCLUDE);
|
|
|
|
/* prior join w/ different source is ok */
|
|
|
|
if (retv && retv != -EADDRINUSE)
|
|
|
|
return retv;
|
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 1;
|
|
|
|
} else /* MCAST_LEAVE_SOURCE_GROUP */ {
|
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 0;
|
|
|
|
}
|
2020-07-17 06:23:30 +00:00
|
|
|
return ip6_mc_source(add, omode, sk, &greqs);
|
2020-04-27 15:00:01 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
|
2020-07-17 06:23:28 +00:00
|
|
|
int optlen)
|
|
|
|
{
|
|
|
|
struct group_filter *gsf;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (optlen < GROUP_FILTER_SIZE(0))
|
|
|
|
return -EINVAL;
|
|
|
|
if (optlen > sysctl_optmem_max)
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
gsf = memdup_sockptr(optval, optlen);
|
2020-07-17 06:23:28 +00:00
|
|
|
if (IS_ERR(gsf))
|
|
|
|
return PTR_ERR(gsf);
|
|
|
|
|
|
|
|
/* numsrc >= (4G-140)/128 overflow in 32 bits */
|
|
|
|
ret = -ENOBUFS;
|
|
|
|
if (gsf->gf_numsrc >= 0x1ffffffU ||
|
|
|
|
gsf->gf_numsrc > sysctl_mld_max_msf)
|
|
|
|
goto out_free_gsf;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
|
|
|
|
goto out_free_gsf;
|
|
|
|
|
|
|
|
ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist);
|
|
|
|
out_free_gsf:
|
|
|
|
kfree(gsf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
|
2020-07-17 06:23:28 +00:00
|
|
|
int optlen)
|
|
|
|
{
|
|
|
|
const int size0 = offsetof(struct compat_group_filter, gf_slist);
|
|
|
|
struct compat_group_filter *gf32;
|
|
|
|
void *p;
|
|
|
|
int ret;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (optlen < size0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (optlen > sysctl_optmem_max - 4)
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
p = kmalloc(optlen + 4, GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
|
|
|
|
ret = -EFAULT;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(gf32, optval, optlen))
|
2020-07-17 06:23:28 +00:00
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
/* numsrc >= (4G-140)/128 overflow in 32 bits */
|
|
|
|
ret = -ENOBUFS;
|
|
|
|
n = gf32->gf_numsrc;
|
|
|
|
if (n >= 0x1ffffffU || n > sysctl_mld_max_msf)
|
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
|
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
ret = ip6_mc_msfilter(sk, &(struct group_filter){
|
|
|
|
.gf_interface = gf32->gf_interface,
|
|
|
|
.gf_group = gf32->gf_group,
|
|
|
|
.gf_fmode = gf32->gf_fmode,
|
|
|
|
.gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist);
|
|
|
|
|
|
|
|
out_free_p:
|
|
|
|
kfree(p);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-17 06:23:29 +00:00
|
|
|
static int ipv6_mcast_join_leave(struct sock *sk, int optname,
|
2020-07-23 06:09:03 +00:00
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 06:23:29 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
struct group_req greq;
|
|
|
|
|
|
|
|
if (optlen < sizeof(greq))
|
|
|
|
return -EINVAL;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&greq, optval, sizeof(greq)))
|
2020-07-17 06:23:29 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (greq.gr_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
psin6 = (struct sockaddr_in6 *)&greq.gr_group;
|
|
|
|
if (optname == MCAST_JOIN_GROUP)
|
|
|
|
return ipv6_sock_mc_join(sk, greq.gr_interface,
|
|
|
|
&psin6->sin6_addr);
|
|
|
|
return ipv6_sock_mc_drop(sk, greq.gr_interface, &psin6->sin6_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname,
|
2020-07-23 06:09:03 +00:00
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 06:23:29 +00:00
|
|
|
{
|
|
|
|
struct compat_group_req gr32;
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
|
|
|
|
if (optlen < sizeof(gr32))
|
|
|
|
return -EINVAL;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
|
2020-07-17 06:23:29 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (gr32.gr_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
psin6 = (struct sockaddr_in6 *)&gr32.gr_group;
|
|
|
|
if (optname == MCAST_JOIN_GROUP)
|
2020-07-17 06:23:30 +00:00
|
|
|
return ipv6_sock_mc_join(sk, gr32.gr_interface,
|
2020-07-17 06:23:29 +00:00
|
|
|
&psin6->sin6_addr);
|
2020-07-17 06:23:30 +00:00
|
|
|
return ipv6_sock_mc_drop(sk, gr32.gr_interface, &psin6->sin6_addr);
|
2020-07-17 06:23:29 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
|
2020-07-23 06:09:02 +00:00
|
|
|
int optlen)
|
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
struct ipv6_opt_hdr *new = NULL;
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
struct ipv6_txoptions *opt;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* hop-by-hop / destination options are privileged option */
|
|
|
|
if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
/* remove any sticky options header with a zero option
|
|
|
|
* length, per RFC3542.
|
|
|
|
*/
|
|
|
|
if (optlen > 0) {
|
2020-07-23 06:09:03 +00:00
|
|
|
if (sockptr_is_null(optval))
|
2020-07-23 06:09:02 +00:00
|
|
|
return -EINVAL;
|
|
|
|
if (optlen < sizeof(struct ipv6_opt_hdr) ||
|
|
|
|
optlen & 0x7 ||
|
|
|
|
optlen > 8 * 255)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
new = memdup_sockptr(optval, optlen);
|
2020-07-23 06:09:02 +00:00
|
|
|
if (IS_ERR(new))
|
|
|
|
return PTR_ERR(new);
|
|
|
|
if (unlikely(ipv6_optlen(new) > optlen)) {
|
|
|
|
kfree(new);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
|
|
|
|
opt = ipv6_renew_options(sk, opt, optname, new);
|
|
|
|
kfree(new);
|
|
|
|
if (IS_ERR(opt))
|
|
|
|
return PTR_ERR(opt);
|
|
|
|
|
|
|
|
/* routing header option needs extra check */
|
|
|
|
err = -EINVAL;
|
|
|
|
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
|
|
|
|
struct ipv6_rt_hdr *rthdr = opt->srcrt;
|
|
|
|
switch (rthdr->type) {
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
|
|
|
case IPV6_SRCRT_TYPE_2:
|
|
|
|
if (rthdr->hdrlen != 2 || rthdr->segments_left != 1)
|
|
|
|
goto sticky_done;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case IPV6_SRCRT_TYPE_4:
|
|
|
|
{
|
|
|
|
struct ipv6_sr_hdr *srh =
|
|
|
|
(struct ipv6_sr_hdr *)opt->srcrt;
|
|
|
|
|
|
|
|
if (!seg6_validate_srh(srh, optlen, false))
|
|
|
|
goto sticky_done;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
goto sticky_done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
opt = ipv6_update_options(sk, opt);
|
|
|
|
sticky_done:
|
|
|
|
if (opt) {
|
|
|
|
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
|
|
|
|
txopt_put(opt);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
2020-07-23 06:09:03 +00:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
2008-03-25 17:26:21 +00:00
|
|
|
struct net *net = sock_net(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
int val, valbool;
|
|
|
|
int retv = -ENOPROTOOPT;
|
2015-03-18 17:50:42 +00:00
|
|
|
bool needs_rtnl = setsockopt_needs_rtnl(optname);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
if (sockptr_is_null(optval))
|
2014-08-24 20:53:10 +00:00
|
|
|
val = 0;
|
2008-04-12 03:59:42 +00:00
|
|
|
else {
|
|
|
|
if (optlen >= sizeof(int)) {
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&val, optval, sizeof(val)))
|
2008-04-12 03:59:42 +00:00
|
|
|
return -EFAULT;
|
|
|
|
} else
|
|
|
|
val = 0;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-08-24 20:53:10 +00:00
|
|
|
valbool = (val != 0);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-04-03 00:22:53 +00:00
|
|
|
if (ip6_mroute_opt(optname))
|
2020-07-23 06:09:03 +00:00
|
|
|
return ip6_mroute_setsockopt(sk, optname, optval, optlen);
|
2008-04-03 00:22:53 +00:00
|
|
|
|
2015-03-18 17:50:42 +00:00
|
|
|
if (needs_rtnl)
|
|
|
|
rtnl_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
|
|
|
|
case IPV6_ADDRFORM:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val == PF_INET) {
|
|
|
|
struct ipv6_txoptions *opt;
|
|
|
|
struct sk_buff *pktopt;
|
|
|
|
|
2008-06-04 11:49:06 +00:00
|
|
|
if (sk->sk_type == SOCK_RAW)
|
|
|
|
break;
|
|
|
|
|
2008-06-04 11:49:08 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
|
sk->sk_protocol == IPPROTO_UDPLITE) {
|
|
|
|
struct udp_sock *up = udp_sk(sk);
|
|
|
|
if (up->pending == AF_INET6) {
|
|
|
|
retv = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
2020-06-01 03:55:03 +00:00
|
|
|
} else if (sk->sk_protocol == IPPROTO_TCP) {
|
|
|
|
if (sk->sk_prot != &tcpv6_prot) {
|
|
|
|
retv = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-25 19:52:29 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-06-01 03:55:03 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (sk->sk_state != TCP_ESTABLISHED) {
|
|
|
|
retv = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6_only_sock(sk) ||
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-03 22:42:29 +00:00
|
|
|
!ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fl6_free_socklist(sk);
|
2016-10-20 06:35:12 +00:00
|
|
|
__ipv6_sock_mc_close(sk);
|
ipv6: fix memory leaks on IPV6_ADDRFORM path
IPV6_ADDRFORM causes resource leaks when converting an IPv6 socket
to IPv4, particularly struct ipv6_ac_socklist. Similar to
struct ipv6_mc_socklist, we should just close it on this path.
This bug can be easily reproduced with the following C program:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main()
{
int s, value;
struct sockaddr_in6 addr;
struct ipv6_mreq m6;
s = socket(AF_INET6, SOCK_DGRAM, 0);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(5000);
inet_pton(AF_INET6, "::ffff:192.168.122.194", &addr.sin6_addr);
connect(s, (struct sockaddr *)&addr, sizeof(addr));
inet_pton(AF_INET6, "fe80::AAAA", &m6.ipv6mr_multiaddr);
m6.ipv6mr_interface = 5;
setsockopt(s, SOL_IPV6, IPV6_JOIN_ANYCAST, &m6, sizeof(m6));
value = AF_INET;
setsockopt(s, SOL_IPV6, IPV6_ADDRFORM, &value, sizeof(value));
close(s);
return 0;
}
Reported-by: ch3332xr@gmail.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-25 22:40:53 +00:00
|
|
|
__ipv6_sock_ac_close(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2005-08-10 02:45:38 +00:00
|
|
|
/*
|
|
|
|
* Sock is moving from IPv6 to IPv4 (sk_prot), so
|
|
|
|
* remove it from the refcnt debug socks count in the
|
|
|
|
* original family...
|
|
|
|
*/
|
|
|
|
sk_refcnt_debug_dec(sk);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_TCP) {
|
2005-12-14 07:26:10 +00:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_disable();
|
2008-04-01 02:41:46 +00:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, &tcp_prot, 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_enable();
|
|
|
|
sk->sk_prot = &tcp_prot;
|
2005-12-14 07:26:10 +00:00
|
|
|
icsk->icsk_af_ops = &ipv4_specific;
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_socket->ops = &inet_stream_ops;
|
|
|
|
sk->sk_family = PF_INET;
|
2005-12-14 07:26:10 +00:00
|
|
|
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2006-11-27 19:10:57 +00:00
|
|
|
struct proto *prot = &udp_prot;
|
|
|
|
|
2008-03-07 00:22:02 +00:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDPLITE)
|
2006-11-27 19:10:57 +00:00
|
|
|
prot = &udplite_prot;
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_disable();
|
2008-04-01 02:41:46 +00:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, prot, 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
local_bh_enable();
|
2006-11-27 19:10:57 +00:00
|
|
|
sk->sk_prot = prot;
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_socket->ops = &inet_dgram_ops;
|
|
|
|
sk->sk_family = PF_INET;
|
|
|
|
}
|
2015-11-30 03:37:57 +00:00
|
|
|
opt = xchg((__force struct ipv6_txoptions **)&np->opt,
|
|
|
|
NULL);
|
|
|
|
if (opt) {
|
|
|
|
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
|
|
|
|
txopt_put(opt);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
pktopt = xchg(&np->pktoptions, NULL);
|
2009-02-23 21:45:33 +00:00
|
|
|
kfree_skb(pktopt);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2005-08-10 02:45:38 +00:00
|
|
|
/*
|
|
|
|
* ... and add it to the refcnt debug socks count
|
|
|
|
* in the new family. -acme
|
|
|
|
*/
|
|
|
|
sk_refcnt_debug_inc(sk);
|
2005-04-16 22:20:36 +00:00
|
|
|
module_put(THIS_MODULE);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int) ||
|
2009-10-15 06:30:45 +00:00
|
|
|
inet_sk(sk)->inet_num)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
2014-06-27 15:36:16 +00:00
|
|
|
sk->sk_ipv6only = valbool;
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVPKTINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 14:24:49 +00:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.rxoinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVHOPLIMIT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxhlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPLIMIT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.rxohlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 04:28:48 +00:00
|
|
|
np->rxopt.bits.srcrt = valbool;
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292RTHDR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 04:28:48 +00:00
|
|
|
np->rxopt.bits.osrcrt = valbool;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.hopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.ohopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.dstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292DSTOPTS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
np->rxopt.bits.odstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_TCLASS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2006-09-14 03:08:07 +00:00
|
|
|
if (val < -1 || val > 0xff)
|
2005-09-08 01:19:03 +00:00
|
|
|
goto e_inval;
|
inet6: Set default traffic class
This patch addresses:
* assigning -1 to np->tclass as it is currently done is not very meaningful,
since it turns into 0xff;
* RFC 3542, 6.5 allows -1 for clearing the sticky IPV6_TCLASS option
and specifies -1 to mean "use kernel default":
- RFC 2460, 7. requires that the default traffic class must be zero for
all 8 bits,
- this is consistent with RFC 2474, 4.1 which recommends a default PHB of 0,
in combination with a value of the ECN field of "non-ECT" (RFC 3168, 5.).
This patch changes the meaning of -1 from assigning 255 to mean the RFC 2460
default, which at the same time allows to satisfy clearing the sticky TCLASS
option as per RFC 3542, 6.5.
(When passing -1 as ancillary data, the fallback remains np->tclass, which
has either been set via socket options, or contains the default value.)
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-08-09 08:12:49 +00:00
|
|
|
/* RFC 3542, 6.5: default traffic class of 0x0 */
|
|
|
|
if (val == -1)
|
|
|
|
val = 0;
|
2005-09-08 01:19:03 +00:00
|
|
|
np->tclass = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 14:24:49 +00:00
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_RECVTCLASS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-09-08 01:19:03 +00:00
|
|
|
np->rxopt.bits.rxtclass = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_FLOWINFO:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->rxopt.bits.rxflow = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-04-23 11:26:07 +00:00
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->rxopt.bits.rxpmtu = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-10-21 14:08:28 +00:00
|
|
|
case IPV6_TRANSPARENT:
|
2019-11-21 21:19:08 +00:00
|
|
|
if (valbool && !ns_capable(net->user_ns, CAP_NET_RAW) &&
|
|
|
|
!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
|
2010-10-23 04:48:14 +00:00
|
|
|
retv = -EPERM;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-21 14:08:28 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
|
|
|
|
inet_sk(sk)->transparent = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 04:32:42 +00:00
|
|
|
case IPV6_FREEBIND:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
/* we also don't have a separate freebind bit for IPV6 */
|
|
|
|
inet_sk(sk)->freebind = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-10-21 14:08:28 +00:00
|
|
|
case IPV6_RECVORIGDSTADDR:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->rxopt.bits.rxorigdstaddr = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
2020-07-23 06:09:02 +00:00
|
|
|
retv = ipv6_set_opt_hdr(sk, optname, optval, optlen);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
break;
|
|
|
|
|
2008-12-16 10:06:23 +00:00
|
|
|
case IPV6_PKTINFO:
|
|
|
|
{
|
|
|
|
struct in6_pktinfo pkt;
|
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto e_inval;
|
2020-07-23 06:09:03 +00:00
|
|
|
else if (optlen < sizeof(struct in6_pktinfo) ||
|
|
|
|
sockptr_is_null(optval))
|
2008-12-16 10:06:23 +00:00
|
|
|
goto e_inval;
|
|
|
|
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&pkt, optval, sizeof(pkt))) {
|
|
|
|
retv = -EFAULT;
|
|
|
|
break;
|
2008-12-16 10:06:23 +00:00
|
|
|
}
|
2018-11-07 15:36:08 +00:00
|
|
|
if (!sk_dev_equal_l3scope(sk, pkt.ipi6_ifindex))
|
2008-12-16 10:06:23 +00:00
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
|
2011-11-21 03:39:03 +00:00
|
|
|
np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr;
|
2008-12-16 10:06:23 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ipv6_txoptions *opt = NULL;
|
|
|
|
struct msghdr msg;
|
2011-03-12 21:22:43 +00:00
|
|
|
struct flowi6 fl6;
|
2016-05-03 04:40:07 +00:00
|
|
|
struct ipcm6_cookie ipc6;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-03-12 21:22:43 +00:00
|
|
|
memset(&fl6, 0, sizeof(fl6));
|
|
|
|
fl6.flowi6_oif = sk->sk_bound_dev_if;
|
|
|
|
fl6.flowi6_mark = sk->sk_mark;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto update;
|
|
|
|
|
|
|
|
/* 1K is probably excessive
|
|
|
|
* 1K is surely not enough, 2K per standard header is 16K.
|
|
|
|
*/
|
|
|
|
retv = -EINVAL;
|
|
|
|
if (optlen > 64*1024)
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
|
|
|
|
retv = -ENOBUFS;
|
2015-03-29 13:00:04 +00:00
|
|
|
if (!opt)
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
memset(opt, 0, sizeof(*opt));
|
2017-07-04 06:34:54 +00:00
|
|
|
refcount_set(&opt->refcnt, 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
opt->tot_len = sizeof(*opt) + optlen;
|
|
|
|
retv = -EFAULT;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(opt + 1, optval, optlen))
|
2005-04-16 22:20:36 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
msg.msg_controllen = optlen;
|
2014-08-24 20:53:10 +00:00
|
|
|
msg.msg_control = (void *)(opt+1);
|
2016-05-03 04:40:07 +00:00
|
|
|
ipc6.opt = opt;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-07-06 14:12:57 +00:00
|
|
|
retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (retv)
|
|
|
|
goto done;
|
|
|
|
update:
|
|
|
|
retv = 0;
|
2008-04-14 06:21:52 +00:00
|
|
|
opt = ipv6_update_options(sk, opt);
|
2005-04-16 22:20:36 +00:00
|
|
|
done:
|
2015-11-30 03:37:57 +00:00
|
|
|
if (opt) {
|
|
|
|
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
|
|
|
|
txopt_put(opt);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_UNICAST_HOPS:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val > 255 || val < -1)
|
|
|
|
goto e_inval;
|
|
|
|
np->hop_limit = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
2008-06-11 18:27:26 +00:00
|
|
|
break;
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val > 255 || val < -1)
|
|
|
|
goto e_inval;
|
2011-11-27 21:33:34 +00:00
|
|
|
np->mcast_hops = (val == -1 ? IPV6_DEFAULT_MCASTHOPS : val);
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2008-06-11 18:14:51 +00:00
|
|
|
if (val != valbool)
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->mc_loop = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2012-02-08 09:11:08 +00:00
|
|
|
case IPV6_UNICAST_IF:
|
|
|
|
{
|
|
|
|
struct net_device *dev = NULL;
|
|
|
|
int ifindex;
|
|
|
|
|
|
|
|
if (optlen != sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
ifindex = (__force int)ntohl((__force __be32)val);
|
|
|
|
if (ifindex == 0) {
|
|
|
|
np->ucast_oif = 0;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = dev_get_by_index(net, ifindex);
|
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
if (!dev)
|
|
|
|
break;
|
|
|
|
dev_put(dev);
|
|
|
|
|
|
|
|
retv = -EINVAL;
|
|
|
|
if (sk->sk_bound_dev_if)
|
|
|
|
break;
|
|
|
|
|
|
|
|
np->ucast_oif = ifindex;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
2008-06-11 18:27:26 +00:00
|
|
|
break;
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-11 21:39:29 +00:00
|
|
|
if (val) {
|
2009-10-19 06:41:58 +00:00
|
|
|
struct net_device *dev;
|
2016-12-29 23:39:37 +00:00
|
|
|
int midx;
|
2009-10-19 06:41:58 +00:00
|
|
|
|
2016-12-29 23:39:37 +00:00
|
|
|
rcu_read_lock();
|
2007-10-11 21:39:29 +00:00
|
|
|
|
2016-12-29 23:39:37 +00:00
|
|
|
dev = dev_get_by_index_rcu(net, val);
|
2009-10-19 06:41:58 +00:00
|
|
|
if (!dev) {
|
2016-12-29 23:39:37 +00:00
|
|
|
rcu_read_unlock();
|
2007-10-11 21:39:29 +00:00
|
|
|
retv = -ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
2016-12-29 23:39:37 +00:00
|
|
|
midx = l3mdev_master_ifindex_rcu(dev);
|
|
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
if (sk->sk_bound_dev_if &&
|
|
|
|
sk->sk_bound_dev_if != val &&
|
|
|
|
(!midx || midx != sk->sk_bound_dev_if))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
np->mcast_oif = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_ADD_MEMBERSHIP:
|
|
|
|
case IPV6_DROP_MEMBERSHIP:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
|
|
|
goto e_inval;
|
|
|
|
|
2007-08-25 05:16:39 +00:00
|
|
|
retv = -EPROTO;
|
|
|
|
if (inet_sk(sk)->is_icsk)
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
retv = -EFAULT;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_ADD_MEMBERSHIP)
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-18 17:50:43 +00:00
|
|
|
retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
2005-04-16 22:20:36 +00:00
|
|
|
else
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-18 17:50:43 +00:00
|
|
|
retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_JOIN_ANYCAST:
|
|
|
|
case IPV6_LEAVE_ANYCAST:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 01:42:07 +00:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
retv = -EFAULT;
|
2020-07-23 06:09:03 +00:00
|
|
|
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_JOIN_ANYCAST)
|
|
|
|
retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
else
|
|
|
|
retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
break;
|
|
|
|
}
|
2018-09-10 08:27:15 +00:00
|
|
|
case IPV6_MULTICAST_ALL:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->mc_all = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case MCAST_JOIN_GROUP:
|
|
|
|
case MCAST_LEAVE_GROUP:
|
2020-07-17 06:23:30 +00:00
|
|
|
if (in_compat_syscall())
|
|
|
|
retv = compat_ipv6_mcast_join_leave(sk, optname, optval,
|
|
|
|
optlen);
|
|
|
|
else
|
|
|
|
retv = ipv6_mcast_join_leave(sk, optname, optval,
|
|
|
|
optlen);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case MCAST_JOIN_SOURCE_GROUP:
|
|
|
|
case MCAST_LEAVE_SOURCE_GROUP:
|
|
|
|
case MCAST_BLOCK_SOURCE:
|
|
|
|
case MCAST_UNBLOCK_SOURCE:
|
2020-07-17 06:23:30 +00:00
|
|
|
retv = do_ipv6_mcast_group_source(sk, optname, optval, optlen);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case MCAST_MSFILTER:
|
2020-07-17 06:23:30 +00:00
|
|
|
if (in_compat_syscall())
|
|
|
|
retv = compat_ipv6_set_mcast_msfilter(sk, optval,
|
|
|
|
optlen);
|
|
|
|
else
|
|
|
|
retv = ipv6_set_mcast_msfilter(sk, optval, optlen);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case IPV6_ROUTER_ALERT:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2008-07-19 07:28:58 +00:00
|
|
|
retv = ip6_ra_control(sk, val);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
2019-03-01 23:31:03 +00:00
|
|
|
case IPV6_ROUTER_ALERT_ISOLATE:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->rtalert_isolate = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_MTU_DISCOVER:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2014-02-26 00:20:43 +00:00
|
|
|
if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto e_inval;
|
|
|
|
np->pmtudisc = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_MTU:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (val && val < IPV6_MIN_MTU)
|
|
|
|
goto e_inval;
|
|
|
|
np->frag_size = val;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_RECVERR:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->recverr = valbool;
|
|
|
|
if (!val)
|
|
|
|
skb_queue_purge(&sk->sk_error_queue);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_FLOWINFO_SEND:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-16 22:20:36 +00:00
|
|
|
np->sndflow = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
case IPV6_FLOWLABEL_MGR:
|
2020-07-23 06:09:03 +00:00
|
|
|
retv = ipv6_flowlabel_opt(sk, optval, optlen);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
case IPV6_IPSEC_POLICY:
|
|
|
|
case IPV6_XFRM_POLICY:
|
2005-08-06 13:33:15 +00:00
|
|
|
retv = -EPERM;
|
net: Allow userns root to control ipv6
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.
Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.
In general policy and network stack state changes are allowed while
resource control is left unchanged.
Allow the SIOCSIFADDR ioctl to add ipv6 addresses.
Allow the SIOCDIFADDR ioctl to delete ipv6 addresses.
Allow the SIOCADDRT ioctl to add ipv6 routes.
Allow the SIOCDELRT ioctl to delete ipv6 routes.
Allow creation of ipv6 raw sockets.
Allow setting the IPV6_JOIN_ANYCAST socket option.
Allow setting the IPV6_FL_A_RENEW parameter of the IPV6_FLOWLABEL_MGR
socket option.
Allow setting the IPV6_TRANSPARENT socket option.
Allow setting the IPV6_HOPOPTS socket option.
Allow setting the IPV6_RTHDRDSTOPTS socket option.
Allow setting the IPV6_DSTOPTS socket option.
Allow setting the IPV6_IPSEC_POLICY socket option.
Allow setting the IPV6_XFRM_POLICY socket option.
Allow sending packets with the IPV6_2292HOPOPTS control message.
Allow sending packets with the IPV6_2292DSTOPTS control message.
Allow sending packets with the IPV6_RTHDRDSTOPTS control message.
Allow setting the multicast routing socket options on non multicast
routing sockets.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL, and SIOCDELTUNNEL ioctls for
setting up, changing and deleting tunnels over ipv6.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL, SIOCDELTUNNEL ioctls for
setting up, changing and deleting ipv6 over ipv4 tunnels.
Allow the SIOCADDPRL, SIOCDELPRL, SIOCCHGPRL ioctls for adding,
deleting, and changing the potential router list for ISATAP tunnels.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-11-16 03:03:06 +00:00
|
|
|
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
2005-08-06 13:33:15 +00:00
|
|
|
break;
|
2020-07-23 06:09:03 +00:00
|
|
|
retv = xfrm_user_policy(sk, optname, optval, optlen);
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
2008-03-25 00:37:42 +00:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
2008-04-12 03:59:42 +00:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2020-05-28 05:12:33 +00:00
|
|
|
retv = __ip6_sock_set_addr_preferences(sk, val);
|
2008-03-25 00:37:42 +00:00
|
|
|
break;
|
IPv6: Generic TTL Security Mechanism (final version)
This patch adds IPv6 support for RFC5082 Generalized TTL Security Mechanism.
Not to users of mapped address; the IPV6 and IPV4 socket options are seperate.
The server does have to deal with both IPv4 and IPv6 socket options
and the client has to handle the different for each family.
On client:
int ttl = 255;
getaddrinfo(argv[1], argv[2], &hint, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET) {
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
} else if (rp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof(ttl)))
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
...
On server:
int minttl = 255 - maxhops;
getaddrinfo(NULL, port, &hints, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&minttl, sizeof(minttl));
setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0)
break
...
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-04-22 22:24:53 +00:00
|
|
|
case IPV6_MINHOPCOUNT:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
if (val < 0 || val > 255)
|
|
|
|
goto e_inval;
|
|
|
|
np->min_hopcount = val;
|
2012-11-10 19:52:34 +00:00
|
|
|
retv = 0;
|
2010-04-23 11:26:07 +00:00
|
|
|
break;
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
np->dontfrag = valbool;
|
IPv6: Generic TTL Security Mechanism (final version)
This patch adds IPv6 support for RFC5082 Generalized TTL Security Mechanism.
Not to users of mapped address; the IPV6 and IPV4 socket options are seperate.
The server does have to deal with both IPv4 and IPv6 socket options
and the client has to handle the different for each family.
On client:
int ttl = 255;
getaddrinfo(argv[1], argv[2], &hint, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET) {
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
} else if (rp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof(ttl)))
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
...
On server:
int minttl = 255 - maxhops;
getaddrinfo(NULL, port, &hints, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&minttl, sizeof(minttl));
setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0)
break
...
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-04-22 22:24:53 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
2014-07-02 04:33:10 +00:00
|
|
|
case IPV6_AUTOFLOWLABEL:
|
|
|
|
np->autoflowlabel = valbool;
|
net: reevalulate autoflowlabel setting after sysctl setting
sysctl.ip6.auto_flowlabels is default 1. In our hosts, we set it to 2.
If sockopt doesn't set autoflowlabel, outcome packets from the hosts are
supposed to not include flowlabel. This is true for normal packet, but
not for reset packet.
The reason is ipv6_pinfo.autoflowlabel is set in sock creation. Later if
we change sysctl.ip6.auto_flowlabels, the ipv6_pinfo.autoflowlabel isn't
changed, so the sock will keep the old behavior in terms of auto
flowlabel. Reset packet is suffering from this problem, because reset
packet is sent from a special control socket, which is created at boot
time. Since sysctl.ipv6.auto_flowlabels is 1 by default, the control
socket will always have its ipv6_pinfo.autoflowlabel set, even after
user set sysctl.ipv6.auto_flowlabels to 1, so reset packset will always
have flowlabel. Normal sock created before sysctl setting suffers from
the same issue. We can't even turn off autoflowlabel unless we kill all
socks in the hosts.
To fix this, if IPV6_AUTOFLOWLABEL sockopt is used, we use the
autoflowlabel setting from user, otherwise we always call
ip6_default_np_autolabel() which has the new settings of sysctl.
Note, this changes behavior a little bit. Before commit 42240901f7c4
(ipv6: Implement different admin modes for automatic flow labels), the
autoflowlabel behavior of a sock isn't sticky, eg, if sysctl changes,
existing connection will change autoflowlabel behavior. After that
commit, autoflowlabel behavior is sticky in the whole life of the sock.
With this patch, the behavior isn't sticky again.
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Tom Herbert <tom@quantonium.net>
Signed-off-by: Shaohua Li <shli@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-12-20 20:10:21 +00:00
|
|
|
np->autoflowlabel_set = 1;
|
2014-07-02 04:33:10 +00:00
|
|
|
retv = 0;
|
|
|
|
break;
|
2016-11-02 15:02:17 +00:00
|
|
|
case IPV6_RECVFRAGSIZE:
|
|
|
|
np->rxopt.bits.recvfragsize = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2020-07-24 13:03:10 +00:00
|
|
|
case IPV6_RECVERR_RFC4884:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
if (val < 0 || val > 1)
|
|
|
|
goto e_inval;
|
|
|
|
np->recverr_rfc4884 = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2008-03-25 00:37:42 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
release_sock(sk);
|
2015-03-18 17:50:42 +00:00
|
|
|
if (needs_rtnl)
|
|
|
|
rtnl_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return retv;
|
|
|
|
|
|
|
|
e_inval:
|
|
|
|
release_sock(sk);
|
2015-03-18 17:50:42 +00:00
|
|
|
if (needs_rtnl)
|
|
|
|
rtnl_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-07-23 06:09:07 +00:00
|
|
|
int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
|
|
|
unsigned int optlen)
|
2006-03-21 06:45:21 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
|
|
|
if (level != SOL_IPV6)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2020-07-23 06:09:07 +00:00
|
|
|
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
|
2006-03-21 06:45:21 +00:00
|
|
|
#ifdef CONFIG_NETFILTER
|
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
|
netfilter: on sockopt() acquire sock lock only in the required scope
Syzbot reported several deadlocks in the netfilter area caused by
rtnl lock and socket lock being acquired with a different order on
different code paths, leading to backtraces like the following one:
======================================================
WARNING: possible circular locking dependency detected
4.15.0-rc9+ #212 Not tainted
------------------------------------------------------
syzkaller041579/3682 is trying to acquire lock:
(sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>] lock_sock
include/net/sock.h:1463 [inline]
(sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>]
do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167
but task is already holding lock:
(rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20
net/core/rtnetlink.c:74
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (rtnl_mutex){+.+.}:
__mutex_lock_common kernel/locking/mutex.c:756 [inline]
__mutex_lock+0x16f/0x1a80 kernel/locking/mutex.c:893
mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:908
rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74
register_netdevice_notifier+0xad/0x860 net/core/dev.c:1607
tee_tg_check+0x1a0/0x280 net/netfilter/xt_TEE.c:106
xt_check_target+0x22c/0x7d0 net/netfilter/x_tables.c:845
check_target net/ipv6/netfilter/ip6_tables.c:538 [inline]
find_check_entry.isra.7+0x935/0xcf0
net/ipv6/netfilter/ip6_tables.c:580
translate_table+0xf52/0x1690 net/ipv6/netfilter/ip6_tables.c:749
do_replace net/ipv6/netfilter/ip6_tables.c:1165 [inline]
do_ip6t_set_ctl+0x370/0x5f0 net/ipv6/netfilter/ip6_tables.c:1691
nf_sockopt net/netfilter/nf_sockopt.c:106 [inline]
nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115
ipv6_setsockopt+0x115/0x150 net/ipv6/ipv6_sockglue.c:928
udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422
sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
SYSC_setsockopt net/socket.c:1849 [inline]
SyS_setsockopt+0x189/0x360 net/socket.c:1828
entry_SYSCALL_64_fastpath+0x29/0xa0
-> #0 (sk_lock-AF_INET6){+.+.}:
lock_acquire+0x1d5/0x580 kernel/locking/lockdep.c:3914
lock_sock_nested+0xc2/0x110 net/core/sock.c:2780
lock_sock include/net/sock.h:1463 [inline]
do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167
ipv6_setsockopt+0xd7/0x150 net/ipv6/ipv6_sockglue.c:922
udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422
sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
SYSC_setsockopt net/socket.c:1849 [inline]
SyS_setsockopt+0x189/0x360 net/socket.c:1828
entry_SYSCALL_64_fastpath+0x29/0xa0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(rtnl_mutex);
lock(sk_lock-AF_INET6);
lock(rtnl_mutex);
lock(sk_lock-AF_INET6);
*** DEADLOCK ***
1 lock held by syzkaller041579/3682:
#0: (rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20
net/core/rtnetlink.c:74
The problem, as Florian noted, is that nf_setsockopt() is always
called with the socket held, even if the lock itself is required only
for very tight scopes and only for some operation.
This patch addresses the issues moving the lock_sock() call only
where really needed, namely in ipv*_getorigdst(), so that nf_setsockopt()
does not need anymore to acquire both locks.
Fixes: 22265a5c3c10 ("netfilter: xt_TEE: resolve oif using netdevice notifiers")
Reported-by: syzbot+a4c2dc980ac1af699b36@syzkaller.appspotmail.com
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2018-01-30 18:01:40 +00:00
|
|
|
optname != IPV6_XFRM_POLICY)
|
2020-07-23 06:09:07 +00:00
|
|
|
err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
|
2006-03-21 06:45:21 +00:00
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2007-02-22 13:05:40 +00:00
|
|
|
EXPORT_SYMBOL(ipv6_setsockopt);
|
2006-03-21 06:45:21 +00:00
|
|
|
|
2007-03-07 20:50:46 +00:00
|
|
|
static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
|
2007-03-19 00:35:57 +00:00
|
|
|
int optname, char __user *optval, int len)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
{
|
2007-03-07 20:50:46 +00:00
|
|
|
struct ipv6_opt_hdr *hdr;
|
|
|
|
|
2007-03-19 00:35:57 +00:00
|
|
|
if (!opt)
|
|
|
|
return 0;
|
|
|
|
|
2014-08-24 20:53:10 +00:00
|
|
|
switch (optname) {
|
2007-03-19 00:35:57 +00:00
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
hdr = opt->hopopt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
hdr = opt->dst0opt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
hdr = (struct ipv6_opt_hdr *)opt->srcrt;
|
|
|
|
break;
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
hdr = opt->dst1opt;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL; /* should not happen */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hdr)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return 0;
|
2007-03-07 20:50:46 +00:00
|
|
|
|
2007-03-10 00:19:17 +00:00
|
|
|
len = min_t(unsigned int, len, ipv6_optlen(hdr));
|
2007-08-15 22:07:30 +00:00
|
|
|
if (copy_to_user(optval, hdr, len))
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return -EFAULT;
|
2008-05-28 08:27:28 +00:00
|
|
|
return len;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
}
|
|
|
|
|
2020-07-17 06:23:27 +00:00
|
|
|
static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
|
|
|
|
int __user *optlen, int len)
|
|
|
|
{
|
|
|
|
const int size0 = offsetof(struct group_filter, gf_slist);
|
|
|
|
struct group_filter __user *p = optval;
|
|
|
|
struct group_filter gsf;
|
|
|
|
int num;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (len < size0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&gsf, p, size0))
|
|
|
|
return -EFAULT;
|
|
|
|
if (gsf.gf_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
num = gsf.gf_numsrc;
|
|
|
|
lock_sock(sk);
|
|
|
|
err = ip6_mc_msfget(sk, &gsf, p->gf_slist);
|
|
|
|
if (!err) {
|
|
|
|
if (num > gsf.gf_numsrc)
|
|
|
|
num = gsf.gf_numsrc;
|
|
|
|
if (put_user(GROUP_FILTER_SIZE(num), optlen) ||
|
|
|
|
copy_to_user(p, &gsf, size0))
|
|
|
|
err = -EFAULT;
|
|
|
|
}
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
|
|
|
|
int __user *optlen)
|
|
|
|
{
|
|
|
|
const int size0 = offsetof(struct compat_group_filter, gf_slist);
|
|
|
|
struct compat_group_filter __user *p = optval;
|
|
|
|
struct compat_group_filter gf32;
|
|
|
|
struct group_filter gf;
|
|
|
|
int len, err;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
if (len < size0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (copy_from_user(&gf32, p, size0))
|
|
|
|
return -EFAULT;
|
|
|
|
gf.gf_interface = gf32.gf_interface;
|
|
|
|
gf.gf_fmode = gf32.gf_fmode;
|
|
|
|
num = gf.gf_numsrc = gf32.gf_numsrc;
|
|
|
|
gf.gf_group = gf32.gf_group;
|
|
|
|
|
|
|
|
if (gf.gf_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
err = ip6_mc_msfget(sk, &gf, p->gf_slist);
|
|
|
|
release_sock(sk);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (num > gf.gf_numsrc)
|
|
|
|
num = gf.gf_numsrc;
|
|
|
|
len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32));
|
|
|
|
if (put_user(len, optlen) ||
|
|
|
|
put_user(gf.gf_fmode, &p->gf_fmode) ||
|
|
|
|
put_user(gf.gf_numsrc, &p->gf_numsrc))
|
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
2012-04-15 05:58:06 +00:00
|
|
|
char __user *optval, int __user *optlen, unsigned int flags)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
int len;
|
|
|
|
int val;
|
|
|
|
|
2008-04-03 00:22:53 +00:00
|
|
|
if (ip6_mroute_opt(optname))
|
|
|
|
return ip6_mroute_getsockopt(sk, optname, optval, optlen);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_ADDRFORM:
|
|
|
|
if (sk->sk_protocol != IPPROTO_UDP &&
|
2006-11-27 19:10:57 +00:00
|
|
|
sk->sk_protocol != IPPROTO_UDPLITE &&
|
2005-04-16 22:20:36 +00:00
|
|
|
sk->sk_protocol != IPPROTO_TCP)
|
2008-06-11 18:27:26 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (sk->sk_state != TCP_ESTABLISHED)
|
|
|
|
return -ENOTCONN;
|
|
|
|
val = sk->sk_family;
|
|
|
|
break;
|
|
|
|
case MCAST_MSFILTER:
|
2020-07-17 06:23:30 +00:00
|
|
|
if (in_compat_syscall())
|
|
|
|
return compat_ipv6_get_msfilter(sk, optval, optlen);
|
2020-07-17 06:23:27 +00:00
|
|
|
return ipv6_get_msfilter(sk, optval, optlen, len);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct msghdr msg;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (sk->sk_type != SOCK_STREAM)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
net/ipv6: propagate user pointer annotation
For IPV6_2292PKTOPTIONS, do_ipv6_getsockopt() stores the user pointer
optval in the msg_control field of the msghdr.
Hence, sparse rightfully warns at ./net/ipv6/ipv6_sockglue.c:1151:33:
warning: incorrect type in assignment (different address spaces)
expected void *msg_control
got char [noderef] __user *optval
Since commit 1f466e1f15cf ("net: cleanly handle kernel vs user buffers for
->msg_control"), user pointers shall be stored in the msg_control_user
field, and kernel pointers in the msg_control field. This allows to
propagate __user annotations nicely through this struct.
Store optval in msg_control_user to properly record and propagate the
memory space annotation of this pointer.
Note that msg_control_is_user is set to true, so the key invariant, i.e.,
use msg_control_user if and only if msg_control_is_user is true, holds.
The msghdr is further used in the six alternative put_cmsg() calls, with
msg_control_is_user being true, put_cmsg() picks msg_control_user
preserving the __user annotation and passes that properly to
copy_to_user().
No functional change. No change in object code.
Signed-off-by: Lukas Bulwahn <lukas.bulwahn@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20201127093421.21673-1-lukas.bulwahn@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-11-27 09:34:21 +00:00
|
|
|
msg.msg_control_user = optval;
|
2005-04-16 22:20:36 +00:00
|
|
|
msg.msg_controllen = len;
|
2011-08-19 10:19:07 +00:00
|
|
|
msg.msg_flags = flags;
|
2020-05-13 19:36:41 +00:00
|
|
|
msg.msg_control_is_user = true;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
skb = np->pktoptions;
|
|
|
|
if (skb)
|
2014-01-20 02:43:08 +00:00
|
|
|
ip6_datagram_recv_ctl(sk, &msg, skb);
|
2015-01-21 11:45:42 +00:00
|
|
|
release_sock(sk);
|
|
|
|
if (!skb) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (np->rxopt.bits.rxinfo) {
|
|
|
|
struct in6_pktinfo src_info;
|
2008-12-16 10:07:45 +00:00
|
|
|
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-03 22:42:29 +00:00
|
|
|
src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr;
|
2005-04-16 22:20:36 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxhlim) {
|
|
|
|
int hlim = np->mcast_hops;
|
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
2012-02-09 09:35:49 +00:00
|
|
|
if (np->rxopt.bits.rxtclass) {
|
2014-01-15 09:03:30 +00:00
|
|
|
int tclass = (int)ip6_tclass(np->rcv_flowinfo);
|
|
|
|
|
2012-02-09 09:35:49 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
|
|
|
|
}
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
if (np->rxopt.bits.rxoinfo) {
|
|
|
|
struct in6_pktinfo src_info;
|
2008-12-16 10:07:45 +00:00
|
|
|
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-03 22:42:29 +00:00
|
|
|
src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr :
|
|
|
|
np->sticky_pktinfo.ipi6_addr;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxohlim) {
|
|
|
|
int hlim = np->mcast_hops;
|
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
2013-12-08 14:46:57 +00:00
|
|
|
if (np->rxopt.bits.rxflow) {
|
2013-12-12 16:07:58 +00:00
|
|
|
__be32 flowinfo = np->rcv_flowinfo;
|
|
|
|
|
2013-12-08 14:46:57 +00:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
len -= msg.msg_controllen;
|
|
|
|
return put_user(len, optlen);
|
|
|
|
}
|
|
|
|
case IPV6_MTU:
|
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
2010-04-08 23:03:29 +00:00
|
|
|
|
2007-02-09 14:24:49 +00:00
|
|
|
val = 0;
|
2010-04-08 23:03:29 +00:00
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
2005-04-16 22:20:36 +00:00
|
|
|
val = dst_mtu(dst);
|
2010-04-08 23:03:29 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
if (!val)
|
|
|
|
return -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
2014-06-27 15:36:16 +00:00
|
|
|
val = sk->sk_ipv6only;
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RECVPKTINFO:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.rxinfo;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
val = np->rxopt.bits.rxoinfo;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPLIMIT:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.rxhlim;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
val = np->rxopt.bits.rxohlim;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.srcrt;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
val = np->rxopt.bits.osrcrt;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_HOPOPTS:
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
{
|
2015-11-30 03:37:57 +00:00
|
|
|
struct ipv6_txoptions *opt;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
|
|
|
|
lock_sock(sk);
|
2016-04-05 15:10:15 +00:00
|
|
|
opt = rcu_dereference_protected(np->opt,
|
|
|
|
lockdep_sock_is_held(sk));
|
2015-11-30 03:37:57 +00:00
|
|
|
len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
release_sock(sk);
|
2008-05-28 08:23:47 +00:00
|
|
|
/* check if ipv6_getsockopt_sticky() returns err code */
|
|
|
|
if (len < 0)
|
|
|
|
return len;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
return put_user(len, optlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.hopopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
val = np->rxopt.bits.ohopopts;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2005-04-16 22:20:36 +00:00
|
|
|
val = np->rxopt.bits.dstopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 00:59:17 +00:00
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
val = np->rxopt.bits.odstopts;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 01:19:03 +00:00
|
|
|
case IPV6_TCLASS:
|
|
|
|
val = np->tclass;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVTCLASS:
|
|
|
|
val = np->rxopt.bits.rxtclass;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_FLOWINFO:
|
|
|
|
val = np->rxopt.bits.rxflow;
|
|
|
|
break;
|
|
|
|
|
2010-04-23 11:26:07 +00:00
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
val = np->rxopt.bits.rxpmtu;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_PATHMTU:
|
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
|
|
|
struct ip6_mtuinfo mtuinfo;
|
|
|
|
|
|
|
|
if (len < sizeof(mtuinfo))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
len = sizeof(mtuinfo);
|
|
|
|
memset(&mtuinfo, 0, sizeof(mtuinfo));
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
|
|
|
mtuinfo.ip6m_mtu = dst_mtu(dst);
|
|
|
|
rcu_read_unlock();
|
|
|
|
if (!mtuinfo.ip6m_mtu)
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
|
|
if (put_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
if (copy_to_user(optval, &mtuinfo, len))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-21 14:08:28 +00:00
|
|
|
case IPV6_TRANSPARENT:
|
|
|
|
val = inet_sk(sk)->transparent;
|
|
|
|
break;
|
|
|
|
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 04:32:42 +00:00
|
|
|
case IPV6_FREEBIND:
|
|
|
|
val = inet_sk(sk)->freebind;
|
|
|
|
break;
|
|
|
|
|
2010-10-21 14:08:28 +00:00
|
|
|
case IPV6_RECVORIGDSTADDR:
|
|
|
|
val = np->rxopt.bits.rxorigdstaddr;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
2006-12-13 01:09:49 +00:00
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
|
|
|
|
|
|
|
if (optname == IPV6_UNICAST_HOPS)
|
|
|
|
val = np->hop_limit;
|
|
|
|
else
|
|
|
|
val = np->mcast_hops;
|
|
|
|
|
2010-04-08 23:03:29 +00:00
|
|
|
if (val < 0) {
|
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
2008-03-10 10:00:30 +00:00
|
|
|
val = ip6_dst_hoplimit(dst);
|
2010-04-08 23:03:29 +00:00
|
|
|
rcu_read_unlock();
|
2006-12-13 01:09:49 +00:00
|
|
|
}
|
2010-04-08 23:03:29 +00:00
|
|
|
|
2006-12-13 01:09:49 +00:00
|
|
|
if (val < 0)
|
2008-07-20 05:35:03 +00:00
|
|
|
val = sock_net(sk)->ipv6.devconf_all->hop_limit;
|
2005-04-16 22:20:36 +00:00
|
|
|
break;
|
2006-12-13 01:09:49 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
val = np->mc_loop;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
val = np->mcast_oif;
|
|
|
|
break;
|
|
|
|
|
2018-09-10 08:27:15 +00:00
|
|
|
case IPV6_MULTICAST_ALL:
|
|
|
|
val = np->mc_all;
|
|
|
|
break;
|
|
|
|
|
2012-02-08 09:11:08 +00:00
|
|
|
case IPV6_UNICAST_IF:
|
|
|
|
val = (__force int)htonl((__u32) np->ucast_oif);
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
case IPV6_MTU_DISCOVER:
|
|
|
|
val = np->pmtudisc;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVERR:
|
|
|
|
val = np->recverr;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_FLOWINFO_SEND:
|
|
|
|
val = np->sndflow;
|
|
|
|
break;
|
|
|
|
|
2013-11-07 16:53:12 +00:00
|
|
|
case IPV6_FLOWLABEL_MGR:
|
|
|
|
{
|
|
|
|
struct in6_flowlabel_req freq;
|
2014-01-17 16:15:04 +00:00
|
|
|
int flags;
|
2013-11-07 16:53:12 +00:00
|
|
|
|
|
|
|
if (len < sizeof(freq))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (copy_from_user(&freq, optval, sizeof(freq)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (freq.flr_action != IPV6_FL_A_GET)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
len = sizeof(freq);
|
2014-01-17 16:15:04 +00:00
|
|
|
flags = freq.flr_flags;
|
|
|
|
|
2013-11-07 16:53:12 +00:00
|
|
|
memset(&freq, 0, sizeof(freq));
|
|
|
|
|
2014-01-17 16:15:04 +00:00
|
|
|
val = ipv6_flowlabel_opt_get(sk, &freq, flags);
|
2013-11-07 16:53:12 +00:00
|
|
|
if (val < 0)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
if (put_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
if (copy_to_user(optval, &freq, len))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-25 00:37:42 +00:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
|
|
|
val = 0;
|
|
|
|
|
|
|
|
if (np->srcprefs & IPV6_PREFER_SRC_TMP)
|
|
|
|
val |= IPV6_PREFER_SRC_TMP;
|
|
|
|
else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
|
|
|
|
val |= IPV6_PREFER_SRC_PUBLIC;
|
|
|
|
else {
|
|
|
|
/* XXX: should we return system default? */
|
|
|
|
val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (np->srcprefs & IPV6_PREFER_SRC_COA)
|
|
|
|
val |= IPV6_PREFER_SRC_COA;
|
|
|
|
else
|
|
|
|
val |= IPV6_PREFER_SRC_HOME;
|
|
|
|
break;
|
IPv6: Generic TTL Security Mechanism (final version)
This patch adds IPv6 support for RFC5082 Generalized TTL Security Mechanism.
Not to users of mapped address; the IPV6 and IPV4 socket options are seperate.
The server does have to deal with both IPv4 and IPv6 socket options
and the client has to handle the different for each family.
On client:
int ttl = 255;
getaddrinfo(argv[1], argv[2], &hint, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET) {
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
} else if (rp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof(ttl)))
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
...
On server:
int minttl = 255 - maxhops;
getaddrinfo(NULL, port, &hints, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&minttl, sizeof(minttl));
setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0)
break
...
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-04-22 22:24:53 +00:00
|
|
|
|
|
|
|
case IPV6_MINHOPCOUNT:
|
|
|
|
val = np->min_hopcount;
|
|
|
|
break;
|
2010-04-23 11:26:07 +00:00
|
|
|
|
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
val = np->dontfrag;
|
|
|
|
break;
|
2008-03-25 00:37:42 +00:00
|
|
|
|
2014-07-02 04:33:10 +00:00
|
|
|
case IPV6_AUTOFLOWLABEL:
|
2018-01-22 20:06:42 +00:00
|
|
|
val = ip6_autoflowlabel(sock_net(sk), np);
|
2014-07-02 04:33:10 +00:00
|
|
|
break;
|
|
|
|
|
2016-11-02 15:02:17 +00:00
|
|
|
case IPV6_RECVFRAGSIZE:
|
|
|
|
val = np->rxopt.bits.recvfragsize;
|
|
|
|
break;
|
|
|
|
|
2019-03-01 23:31:03 +00:00
|
|
|
case IPV6_ROUTER_ALERT_ISOLATE:
|
|
|
|
val = np->rtalert_isolate;
|
|
|
|
break;
|
|
|
|
|
2020-07-24 13:03:10 +00:00
|
|
|
case IPV6_RECVERR_RFC4884:
|
|
|
|
val = np->recverr_rfc4884;
|
|
|
|
break;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
default:
|
2007-12-16 21:39:57 +00:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
len = min_t(unsigned int, sizeof(int), len);
|
2014-08-24 20:53:10 +00:00
|
|
|
if (put_user(len, optlen))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EFAULT;
|
2014-08-24 20:53:10 +00:00
|
|
|
if (copy_to_user(optval, &val, len))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 06:45:21 +00:00
|
|
|
int ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
2014-08-24 20:53:10 +00:00
|
|
|
if (level != SOL_IPV6)
|
2006-03-21 06:45:21 +00:00
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2011-08-19 10:19:07 +00:00
|
|
|
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
|
2006-03-21 06:45:21 +00:00
|
|
|
#ifdef CONFIG_NETFILTER
|
2007-12-16 21:39:57 +00:00
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
|
2006-03-21 06:45:21 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2018-02-08 11:19:00 +00:00
|
|
|
err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
|
2006-03-21 06:45:21 +00:00
|
|
|
if (err >= 0)
|
|
|
|
err = put_user(len, optlen);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2007-02-22 13:05:40 +00:00
|
|
|
EXPORT_SYMBOL(ipv6_getsockopt);
|