Commit 471e39df authored by Marcelo Ricardo Leitner's avatar Marcelo Ricardo Leitner Committed by David S. Miller
Browse files

sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket



If a socket is set ipv6only, it will still send IPv4 addresses in the
INIT and INIT_ACK packets. This potentially misleads the peer into using
them, which then would cause association termination.

The fix is to not add IPv4 addresses to ipv6only sockets.

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Reported-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Tested-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6186d41
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -353,11 +353,13 @@ enum {
	 ipv4_is_anycast_6to4(a))

/* Flags used for the bind address copy functions.  */
#define SCTP_ADDR6_ALLOWED	0x00000001	/* IPv6 address is allowed by
#define SCTP_ADDR4_ALLOWED	0x00000001	/* IPv4 address is allowed by
						   local sock family */
#define SCTP_ADDR4_PEERSUPP	0x00000002	/* IPv4 address is supported by
#define SCTP_ADDR6_ALLOWED	0x00000002	/* IPv6 address is allowed by
						   local sock family */
#define SCTP_ADDR4_PEERSUPP	0x00000004	/* IPv4 address is supported by
						   peer */
#define SCTP_ADDR6_PEERSUPP	0x00000004	/* IPv6 address is supported by
#define SCTP_ADDR6_PEERSUPP	0x00000008	/* IPv6 address is supported by
						   peer */

/* Reasons to retransmit. */
+4 −1
Original line number Diff line number Diff line
@@ -1565,12 +1565,15 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
				     enum sctp_scope scope, gfp_t gfp)
{
	struct sock *sk = asoc->base.sk;
	int flags;

	/* Use scoping rules to determine the subset of addresses from
	 * the endpoint.
	 */
	flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
	flags = (PF_INET6 == sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
	if (!inet_v6_ipv6only(sk))
		flags |= SCTP_ADDR4_ALLOWED;
	if (asoc->peer.ipv4_address)
		flags |= SCTP_ADDR4_PEERSUPP;
	if (asoc->peer.ipv6_address)
+1 −0
Original line number Diff line number Diff line
@@ -461,6 +461,7 @@ static int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
		 * well as the remote peer.
		 */
		if ((((AF_INET == addr->sa.sa_family) &&
		      (flags & SCTP_ADDR4_ALLOWED) &&
		      (flags & SCTP_ADDR4_PEERSUPP))) ||
		    (((AF_INET6 == addr->sa.sa_family) &&
		      (flags & SCTP_ADDR6_ALLOWED) &&
+2 −1
Original line number Diff line number Diff line
@@ -148,7 +148,8 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
		 * sock as well as the remote peer.
		 */
		if (addr->a.sa.sa_family == AF_INET &&
		    !(copy_flags & SCTP_ADDR4_PEERSUPP))
		    (!(copy_flags & SCTP_ADDR4_ALLOWED) ||
		     !(copy_flags & SCTP_ADDR4_PEERSUPP)))
			continue;
		if (addr->a.sa.sa_family == AF_INET6 &&
		    (!(copy_flags & SCTP_ADDR6_ALLOWED) ||