All of lore.kernel.org
 help / color / mirror / Atom feed
* Strange problem with SCTP+IPv6
@ 2020-06-21 15:56 ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-21 15:56 UTC (permalink / raw)
  To: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp
  Cc: linux-kernel

I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
then I make a connection to it using ::1, the connection will drop after
2.5 seconds with an ECONNRESET error.

It only happens on SCTP, it doesn't have the issue if you connect to a
full IPv6 address instead of ::1, and it doesn't happen if you don't
set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
I tried on an ARM system and x86_64.

I haven't dug into the kernel to see if I could find anything yet, but I
thought I would go ahead and report it.  I am attaching a reproducer.
Basically, compile the following code:

  gcc -g -o sctptest -Wall sctptest.c

and run it in one window as a server:

  ./sctptest a

(Pass in any option to be the server) and run the following in another
window as the client:

  ./sctptest

It disconnects after about 2.5 seconds.  If it works, it should just sit
there forever.

-corey


#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/sctp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

static int
getaddr(const char *addr, const char *port, bool listen,
	struct addrinfo **rai)
{
    struct addrinfo *ai, hints;

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG;
    if (listen)
	hints.ai_flags |= AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_SCTP;
    if (getaddrinfo(addr, port, &hints, &ai)) {
	perror("getaddrinfo");
	return -1;
    }

    *rai = ai;
    return 0;
}

static int
waitread(int s)
{
    char data[1];
    ssize_t rv;

    rv = read(s, data, sizeof(data));
    if (rv == -1) {
	perror("read");
	return -1;
    }
    printf("Read %d bytes\n", (int) rv);
    return 0;
}

static int
do_server(void)
{
    int err, ls, s, optval;
    struct addrinfo *ai;

    printf("Server\n");

    err = getaddr("::", "3023", true, &ai);
    if (err)
	return err;

    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (ls == -1) {
	perror("socket");
	return -1;
    }

    optval = 1;
    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
		   (void *)&optval, sizeof(optval)) == -1) {
	perror("setsockopt reuseaddr");
	return -1;
    }

    /* Comment this out and it will work. */
    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
		   sizeof(optval)) == -1) {
	perror("setsockopt ipv6 only");
	return -1;
    }

    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
    if (err == -1) {
	perror("bind");
	return -1;
    }

    err = listen(ls, 5);
    if (err == -1) {
	perror("listen");
	return -1;
    }

    s = accept(ls, NULL, NULL);
    if (s == -1) {
	perror("accept");
	return -1;
    }

    close(ls);

    err = waitread(s);
    close(s);
    return err;
}

static int
do_client(void)
{
    int err, s;
    struct addrinfo *ai;

    printf("Client\n");

    err = getaddr("::1", "3023", false, &ai);
    if (err)
	return err;

    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (s == -1) {
	perror("socket");
	return -1;
    }

    err = connect(s, ai->ai_addr, ai->ai_addrlen);
    if (err == -1) {
	perror("connect");
	return -1;
    }

    err = waitread(s);
    close(s);
    return err;
}

int
main(int argc, char *argv[])
{
    int err;

    if (argc > 1)
	err = do_server();
    else
	err = do_client();
    return !!err;
}


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Strange problem with SCTP+IPv6
@ 2020-06-21 15:56 ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-21 15:56 UTC (permalink / raw)
  To: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp
  Cc: linux-kernel

I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
then I make a connection to it using ::1, the connection will drop after
2.5 seconds with an ECONNRESET error.

It only happens on SCTP, it doesn't have the issue if you connect to a
full IPv6 address instead of ::1, and it doesn't happen if you don't
set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
I tried on an ARM system and x86_64.

I haven't dug into the kernel to see if I could find anything yet, but I
thought I would go ahead and report it.  I am attaching a reproducer.
Basically, compile the following code:

  gcc -g -o sctptest -Wall sctptest.c

and run it in one window as a server:

  ./sctptest a

(Pass in any option to be the server) and run the following in another
window as the client:

  ./sctptest

It disconnects after about 2.5 seconds.  If it works, it should just sit
there forever.

-corey


#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/sctp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

static int
getaddr(const char *addr, const char *port, bool listen,
	struct addrinfo **rai)
{
    struct addrinfo *ai, hints;

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG;
    if (listen)
	hints.ai_flags |= AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_SCTP;
    if (getaddrinfo(addr, port, &hints, &ai)) {
	perror("getaddrinfo");
	return -1;
    }

    *rai = ai;
    return 0;
}

static int
waitread(int s)
{
    char data[1];
    ssize_t rv;

    rv = read(s, data, sizeof(data));
    if (rv = -1) {
	perror("read");
	return -1;
    }
    printf("Read %d bytes\n", (int) rv);
    return 0;
}

static int
do_server(void)
{
    int err, ls, s, optval;
    struct addrinfo *ai;

    printf("Server\n");

    err = getaddr("::", "3023", true, &ai);
    if (err)
	return err;

    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (ls = -1) {
	perror("socket");
	return -1;
    }

    optval = 1;
    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
		   (void *)&optval, sizeof(optval)) = -1) {
	perror("setsockopt reuseaddr");
	return -1;
    }

    /* Comment this out and it will work. */
    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
		   sizeof(optval)) = -1) {
	perror("setsockopt ipv6 only");
	return -1;
    }

    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
    if (err = -1) {
	perror("bind");
	return -1;
    }

    err = listen(ls, 5);
    if (err = -1) {
	perror("listen");
	return -1;
    }

    s = accept(ls, NULL, NULL);
    if (s = -1) {
	perror("accept");
	return -1;
    }

    close(ls);

    err = waitread(s);
    close(s);
    return err;
}

static int
do_client(void)
{
    int err, s;
    struct addrinfo *ai;

    printf("Client\n");

    err = getaddr("::1", "3023", false, &ai);
    if (err)
	return err;

    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (s = -1) {
	perror("socket");
	return -1;
    }

    err = connect(s, ai->ai_addr, ai->ai_addrlen);
    if (err = -1) {
	perror("connect");
	return -1;
    }

    err = waitread(s);
    close(s);
    return err;
}

int
main(int argc, char *argv[])
{
    int err;

    if (argc > 1)
	err = do_server();
    else
	err = do_client();
    return !!err;
}

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-21 15:56 ` Corey Minyard
@ 2020-06-22 12:01   ` Xin Long
  -1 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-22 11:52 UTC (permalink / raw)
  To: minyard
  Cc: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp, LKML

On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>
> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> then I make a connection to it using ::1, the connection will drop after
> 2.5 seconds with an ECONNRESET error.
>
> It only happens on SCTP, it doesn't have the issue if you connect to a
> full IPv6 address instead of ::1, and it doesn't happen if you don't
> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> I tried on an ARM system and x86_64.
>
> I haven't dug into the kernel to see if I could find anything yet, but I
> thought I would go ahead and report it.  I am attaching a reproducer.
> Basically, compile the following code:
The code only set IPV6_V6ONLY on server side, so the client side will
still bind all the local ipv4 addresses (as you didn't call bind() to
bind any specific addresses ). Then after the connection is created,
the client will send HB on the v4 paths to the server. The server
will abort the connection, as it can't support v4.

So you can work around it by either:

  - set IPV6_V6ONLY on client side.

or

  - bind to the specific v6 addresses on the client side.

I don't see RFC said something about this.
So it may not be a good idea to change the current behaviour
to not establish the connection in this case, which may cause regression.

>
>   gcc -g -o sctptest -Wall sctptest.c
>
> and run it in one window as a server:
>
>   ./sctptest a
>
> (Pass in any option to be the server) and run the following in another
> window as the client:
>
>   ./sctptest
>
> It disconnects after about 2.5 seconds.  If it works, it should just sit
> there forever.
>
> -corey
>
>
> #include <stdio.h>
> #include <stdbool.h>
> #include <string.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <sys/select.h>
> #include <arpa/inet.h>
> #include <netinet/sctp.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netdb.h>
>
> static int
> getaddr(const char *addr, const char *port, bool listen,
>         struct addrinfo **rai)
> {
>     struct addrinfo *ai, hints;
>
>     memset(&hints, 0, sizeof(hints));
>     hints.ai_flags = AI_ADDRCONFIG;
>     if (listen)
>         hints.ai_flags |= AI_PASSIVE;
>     hints.ai_family = AF_UNSPEC;
>     hints.ai_socktype = SOCK_STREAM;
>     hints.ai_protocol = IPPROTO_SCTP;
>     if (getaddrinfo(addr, port, &hints, &ai)) {
>         perror("getaddrinfo");
>         return -1;
>     }
>
>     *rai = ai;
>     return 0;
> }
>
> static int
> waitread(int s)
> {
>     char data[1];
>     ssize_t rv;
>
>     rv = read(s, data, sizeof(data));
>     if (rv = -1) {
>         perror("read");
>         return -1;
>     }
>     printf("Read %d bytes\n", (int) rv);
>     return 0;
> }
>
> static int
> do_server(void)
> {
>     int err, ls, s, optval;
>     struct addrinfo *ai;
>
>     printf("Server\n");
>
>     err = getaddr("::", "3023", true, &ai);
>     if (err)
>         return err;
>
>     ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>     if (ls = -1) {
>         perror("socket");
>         return -1;
>     }
>
>     optval = 1;
>     if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>                    (void *)&optval, sizeof(optval)) = -1) {
>         perror("setsockopt reuseaddr");
>         return -1;
>     }
>
>     /* Comment this out and it will work. */
>     if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>                    sizeof(optval)) = -1) {
>         perror("setsockopt ipv6 only");
>         return -1;
>     }
>
>     err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>     if (err = -1) {
>         perror("bind");
>         return -1;
>     }
>
>     err = listen(ls, 5);
>     if (err = -1) {
>         perror("listen");
>         return -1;
>     }
>
>     s = accept(ls, NULL, NULL);
>     if (s = -1) {
>         perror("accept");
>         return -1;
>     }
>
>     close(ls);
>
>     err = waitread(s);
>     close(s);
>     return err;
> }
>
> static int
> do_client(void)
> {
>     int err, s;
>     struct addrinfo *ai;
>
>     printf("Client\n");
>
>     err = getaddr("::1", "3023", false, &ai);
>     if (err)
>         return err;
>
>     s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>     if (s = -1) {
>         perror("socket");
>         return -1;
>     }
>
>     err = connect(s, ai->ai_addr, ai->ai_addrlen);
>     if (err = -1) {
>         perror("connect");
>         return -1;
>     }
>
>     err = waitread(s);
>     close(s);
>     return err;
> }
>
> int
> main(int argc, char *argv[])
> {
>     int err;
>
>     if (argc > 1)
>         err = do_server();
>     else
>         err = do_client();
>     return !!err;
> }
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 12:01   ` Xin Long
  0 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-22 12:01 UTC (permalink / raw)
  To: minyard
  Cc: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp, LKML

On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>
> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> then I make a connection to it using ::1, the connection will drop after
> 2.5 seconds with an ECONNRESET error.
>
> It only happens on SCTP, it doesn't have the issue if you connect to a
> full IPv6 address instead of ::1, and it doesn't happen if you don't
> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> I tried on an ARM system and x86_64.
>
> I haven't dug into the kernel to see if I could find anything yet, but I
> thought I would go ahead and report it.  I am attaching a reproducer.
> Basically, compile the following code:
The code only set IPV6_V6ONLY on server side, so the client side will
still bind all the local ipv4 addresses (as you didn't call bind() to
bind any specific addresses ). Then after the connection is created,
the client will send HB on the v4 paths to the server. The server
will abort the connection, as it can't support v4.

So you can work around it by either:

  - set IPV6_V6ONLY on client side.

or

  - bind to the specific v6 addresses on the client side.

I don't see RFC said something about this.
So it may not be a good idea to change the current behaviour
to not establish the connection in this case, which may cause regression.

>
>   gcc -g -o sctptest -Wall sctptest.c
>
> and run it in one window as a server:
>
>   ./sctptest a
>
> (Pass in any option to be the server) and run the following in another
> window as the client:
>
>   ./sctptest
>
> It disconnects after about 2.5 seconds.  If it works, it should just sit
> there forever.
>
> -corey
>
>
> #include <stdio.h>
> #include <stdbool.h>
> #include <string.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <sys/select.h>
> #include <arpa/inet.h>
> #include <netinet/sctp.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netdb.h>
>
> static int
> getaddr(const char *addr, const char *port, bool listen,
>         struct addrinfo **rai)
> {
>     struct addrinfo *ai, hints;
>
>     memset(&hints, 0, sizeof(hints));
>     hints.ai_flags = AI_ADDRCONFIG;
>     if (listen)
>         hints.ai_flags |= AI_PASSIVE;
>     hints.ai_family = AF_UNSPEC;
>     hints.ai_socktype = SOCK_STREAM;
>     hints.ai_protocol = IPPROTO_SCTP;
>     if (getaddrinfo(addr, port, &hints, &ai)) {
>         perror("getaddrinfo");
>         return -1;
>     }
>
>     *rai = ai;
>     return 0;
> }
>
> static int
> waitread(int s)
> {
>     char data[1];
>     ssize_t rv;
>
>     rv = read(s, data, sizeof(data));
>     if (rv == -1) {
>         perror("read");
>         return -1;
>     }
>     printf("Read %d bytes\n", (int) rv);
>     return 0;
> }
>
> static int
> do_server(void)
> {
>     int err, ls, s, optval;
>     struct addrinfo *ai;
>
>     printf("Server\n");
>
>     err = getaddr("::", "3023", true, &ai);
>     if (err)
>         return err;
>
>     ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>     if (ls == -1) {
>         perror("socket");
>         return -1;
>     }
>
>     optval = 1;
>     if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>                    (void *)&optval, sizeof(optval)) == -1) {
>         perror("setsockopt reuseaddr");
>         return -1;
>     }
>
>     /* Comment this out and it will work. */
>     if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>                    sizeof(optval)) == -1) {
>         perror("setsockopt ipv6 only");
>         return -1;
>     }
>
>     err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>     if (err == -1) {
>         perror("bind");
>         return -1;
>     }
>
>     err = listen(ls, 5);
>     if (err == -1) {
>         perror("listen");
>         return -1;
>     }
>
>     s = accept(ls, NULL, NULL);
>     if (s == -1) {
>         perror("accept");
>         return -1;
>     }
>
>     close(ls);
>
>     err = waitread(s);
>     close(s);
>     return err;
> }
>
> static int
> do_client(void)
> {
>     int err, s;
>     struct addrinfo *ai;
>
>     printf("Client\n");
>
>     err = getaddr("::1", "3023", false, &ai);
>     if (err)
>         return err;
>
>     s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>     if (s == -1) {
>         perror("socket");
>         return -1;
>     }
>
>     err = connect(s, ai->ai_addr, ai->ai_addrlen);
>     if (err == -1) {
>         perror("connect");
>         return -1;
>     }
>
>     err = waitread(s);
>     close(s);
>     return err;
> }
>
> int
> main(int argc, char *argv[])
> {
>     int err;
>
>     if (argc > 1)
>         err = do_server();
>     else
>         err = do_client();
>     return !!err;
> }
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 12:01   ` Xin Long
@ 2020-06-22 12:32     ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 12:32 UTC (permalink / raw)
  To: Xin Long
  Cc: minyard, Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner,
	linux-sctp, LKML



> On 22. Jun 2020, at 14:01, Xin Long <lucien.xin@gmail.com> wrote:
> 
> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>> 
>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>> then I make a connection to it using ::1, the connection will drop after
>> 2.5 seconds with an ECONNRESET error.
>> 
>> It only happens on SCTP, it doesn't have the issue if you connect to a
>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>> I tried on an ARM system and x86_64.
>> 
>> I haven't dug into the kernel to see if I could find anything yet, but I
>> thought I would go ahead and report it.  I am attaching a reproducer.
>> Basically, compile the following code:
> The code only set IPV6_V6ONLY on server side, so the client side will
> still bind all the local ipv4 addresses (as you didn't call bind() to
> bind any specific addresses ). Then after the connection is created,
Let's focus on the loopback addresses ::1 and 127.0.0.1.

So the server will only use ::1. The client will send an INIT from
::1 to ::1 and lists 127.0.0.1 and ::1. That is what I would expect.
Is that happening?

The server would respond with an INIT-ACK from ::1 to ::1 and would
not list any IP addresses. Especially not 127.0.0.1, since it is IPv6 only.

After the association has beed established, the client can't send
any IPv4 packet to the server, since the server did not announce
any. The server can't send any IPv4 packets since it is IPv6 only.

This is what I would expect and this scenario should just work.
What am I missing?

Best regards
Michael
> the client will send HB on the v4 paths to the server. The server
> will abort the connection, as it can't support v4.
> 
> So you can work around it by either:
> 
>  - set IPV6_V6ONLY on client side.
> 
> or
> 
>  - bind to the specific v6 addresses on the client side.
> 
> I don't see RFC said something about this.
> So it may not be a good idea to change the current behaviour
> to not establish the connection in this case, which may cause regression.
> 
>> 
>>  gcc -g -o sctptest -Wall sctptest.c
>> 
>> and run it in one window as a server:
>> 
>>  ./sctptest a
>> 
>> (Pass in any option to be the server) and run the following in another
>> window as the client:
>> 
>>  ./sctptest
>> 
>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>> there forever.
>> 
>> -corey
>> 
>> 
>> #include <stdio.h>
>> #include <stdbool.h>
>> #include <string.h>
>> #include <unistd.h>
>> #include <fcntl.h>
>> #include <sys/select.h>
>> #include <arpa/inet.h>
>> #include <netinet/sctp.h>
>> #include <sys/types.h>
>> #include <sys/socket.h>
>> #include <netdb.h>
>> 
>> static int
>> getaddr(const char *addr, const char *port, bool listen,
>>        struct addrinfo **rai)
>> {
>>    struct addrinfo *ai, hints;
>> 
>>    memset(&hints, 0, sizeof(hints));
>>    hints.ai_flags = AI_ADDRCONFIG;
>>    if (listen)
>>        hints.ai_flags |= AI_PASSIVE;
>>    hints.ai_family = AF_UNSPEC;
>>    hints.ai_socktype = SOCK_STREAM;
>>    hints.ai_protocol = IPPROTO_SCTP;
>>    if (getaddrinfo(addr, port, &hints, &ai)) {
>>        perror("getaddrinfo");
>>        return -1;
>>    }
>> 
>>    *rai = ai;
>>    return 0;
>> }
>> 
>> static int
>> waitread(int s)
>> {
>>    char data[1];
>>    ssize_t rv;
>> 
>>    rv = read(s, data, sizeof(data));
>>    if (rv == -1) {
>>        perror("read");
>>        return -1;
>>    }
>>    printf("Read %d bytes\n", (int) rv);
>>    return 0;
>> }
>> 
>> static int
>> do_server(void)
>> {
>>    int err, ls, s, optval;
>>    struct addrinfo *ai;
>> 
>>    printf("Server\n");
>> 
>>    err = getaddr("::", "3023", true, &ai);
>>    if (err)
>>        return err;
>> 
>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>    if (ls == -1) {
>>        perror("socket");
>>        return -1;
>>    }
>> 
>>    optval = 1;
>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>                   (void *)&optval, sizeof(optval)) == -1) {
>>        perror("setsockopt reuseaddr");
>>        return -1;
>>    }
>> 
>>    /* Comment this out and it will work. */
>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>                   sizeof(optval)) == -1) {
>>        perror("setsockopt ipv6 only");
>>        return -1;
>>    }
>> 
>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>    if (err == -1) {
>>        perror("bind");
>>        return -1;
>>    }
>> 
>>    err = listen(ls, 5);
>>    if (err == -1) {
>>        perror("listen");
>>        return -1;
>>    }
>> 
>>    s = accept(ls, NULL, NULL);
>>    if (s == -1) {
>>        perror("accept");
>>        return -1;
>>    }
>> 
>>    close(ls);
>> 
>>    err = waitread(s);
>>    close(s);
>>    return err;
>> }
>> 
>> static int
>> do_client(void)
>> {
>>    int err, s;
>>    struct addrinfo *ai;
>> 
>>    printf("Client\n");
>> 
>>    err = getaddr("::1", "3023", false, &ai);
>>    if (err)
>>        return err;
>> 
>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>    if (s == -1) {
>>        perror("socket");
>>        return -1;
>>    }
>> 
>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>    if (err == -1) {
>>        perror("connect");
>>        return -1;
>>    }
>> 
>>    err = waitread(s);
>>    close(s);
>>    return err;
>> }
>> 
>> int
>> main(int argc, char *argv[])
>> {
>>    int err;
>> 
>>    if (argc > 1)
>>        err = do_server();
>>    else
>>        err = do_client();
>>    return !!err;
>> }
>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 12:32     ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 12:32 UTC (permalink / raw)
  To: Xin Long
  Cc: minyard, Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner,
	linux-sctp, LKML



> On 22. Jun 2020, at 14:01, Xin Long <lucien.xin@gmail.com> wrote:
> 
> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>> 
>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>> then I make a connection to it using ::1, the connection will drop after
>> 2.5 seconds with an ECONNRESET error.
>> 
>> It only happens on SCTP, it doesn't have the issue if you connect to a
>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>> I tried on an ARM system and x86_64.
>> 
>> I haven't dug into the kernel to see if I could find anything yet, but I
>> thought I would go ahead and report it.  I am attaching a reproducer.
>> Basically, compile the following code:
> The code only set IPV6_V6ONLY on server side, so the client side will
> still bind all the local ipv4 addresses (as you didn't call bind() to
> bind any specific addresses ). Then after the connection is created,
Let's focus on the loopback addresses ::1 and 127.0.0.1.

So the server will only use ::1. The client will send an INIT from
::1 to ::1 and lists 127.0.0.1 and ::1. That is what I would expect.
Is that happening?

The server would respond with an INIT-ACK from ::1 to ::1 and would
not list any IP addresses. Especially not 127.0.0.1, since it is IPv6 only.

After the association has beed established, the client can't send
any IPv4 packet to the server, since the server did not announce
any. The server can't send any IPv4 packets since it is IPv6 only.

This is what I would expect and this scenario should just work.
What am I missing?

Best regards
Michael
> the client will send HB on the v4 paths to the server. The server
> will abort the connection, as it can't support v4.
> 
> So you can work around it by either:
> 
>  - set IPV6_V6ONLY on client side.
> 
> or
> 
>  - bind to the specific v6 addresses on the client side.
> 
> I don't see RFC said something about this.
> So it may not be a good idea to change the current behaviour
> to not establish the connection in this case, which may cause regression.
> 
>> 
>>  gcc -g -o sctptest -Wall sctptest.c
>> 
>> and run it in one window as a server:
>> 
>>  ./sctptest a
>> 
>> (Pass in any option to be the server) and run the following in another
>> window as the client:
>> 
>>  ./sctptest
>> 
>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>> there forever.
>> 
>> -corey
>> 
>> 
>> #include <stdio.h>
>> #include <stdbool.h>
>> #include <string.h>
>> #include <unistd.h>
>> #include <fcntl.h>
>> #include <sys/select.h>
>> #include <arpa/inet.h>
>> #include <netinet/sctp.h>
>> #include <sys/types.h>
>> #include <sys/socket.h>
>> #include <netdb.h>
>> 
>> static int
>> getaddr(const char *addr, const char *port, bool listen,
>>        struct addrinfo **rai)
>> {
>>    struct addrinfo *ai, hints;
>> 
>>    memset(&hints, 0, sizeof(hints));
>>    hints.ai_flags = AI_ADDRCONFIG;
>>    if (listen)
>>        hints.ai_flags |= AI_PASSIVE;
>>    hints.ai_family = AF_UNSPEC;
>>    hints.ai_socktype = SOCK_STREAM;
>>    hints.ai_protocol = IPPROTO_SCTP;
>>    if (getaddrinfo(addr, port, &hints, &ai)) {
>>        perror("getaddrinfo");
>>        return -1;
>>    }
>> 
>>    *rai = ai;
>>    return 0;
>> }
>> 
>> static int
>> waitread(int s)
>> {
>>    char data[1];
>>    ssize_t rv;
>> 
>>    rv = read(s, data, sizeof(data));
>>    if (rv = -1) {
>>        perror("read");
>>        return -1;
>>    }
>>    printf("Read %d bytes\n", (int) rv);
>>    return 0;
>> }
>> 
>> static int
>> do_server(void)
>> {
>>    int err, ls, s, optval;
>>    struct addrinfo *ai;
>> 
>>    printf("Server\n");
>> 
>>    err = getaddr("::", "3023", true, &ai);
>>    if (err)
>>        return err;
>> 
>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>    if (ls = -1) {
>>        perror("socket");
>>        return -1;
>>    }
>> 
>>    optval = 1;
>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>                   (void *)&optval, sizeof(optval)) = -1) {
>>        perror("setsockopt reuseaddr");
>>        return -1;
>>    }
>> 
>>    /* Comment this out and it will work. */
>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>                   sizeof(optval)) = -1) {
>>        perror("setsockopt ipv6 only");
>>        return -1;
>>    }
>> 
>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>    if (err = -1) {
>>        perror("bind");
>>        return -1;
>>    }
>> 
>>    err = listen(ls, 5);
>>    if (err = -1) {
>>        perror("listen");
>>        return -1;
>>    }
>> 
>>    s = accept(ls, NULL, NULL);
>>    if (s = -1) {
>>        perror("accept");
>>        return -1;
>>    }
>> 
>>    close(ls);
>> 
>>    err = waitread(s);
>>    close(s);
>>    return err;
>> }
>> 
>> static int
>> do_client(void)
>> {
>>    int err, s;
>>    struct addrinfo *ai;
>> 
>>    printf("Client\n");
>> 
>>    err = getaddr("::1", "3023", false, &ai);
>>    if (err)
>>        return err;
>> 
>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>    if (s = -1) {
>>        perror("socket");
>>        return -1;
>>    }
>> 
>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>    if (err = -1) {
>>        perror("connect");
>>        return -1;
>>    }
>> 
>>    err = waitread(s);
>>    close(s);
>>    return err;
>> }
>> 
>> int
>> main(int argc, char *argv[])
>> {
>>    int err;
>> 
>>    if (argc > 1)
>>        err = do_server();
>>    else
>>        err = do_client();
>>    return !!err;
>> }
>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 12:01   ` Xin Long
@ 2020-06-22 16:57     ` Corey Minyard
  -1 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-22 16:57 UTC (permalink / raw)
  To: Xin Long
  Cc: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp, LKML

On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >
> > I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > then I make a connection to it using ::1, the connection will drop after
> > 2.5 seconds with an ECONNRESET error.
> >
> > It only happens on SCTP, it doesn't have the issue if you connect to a
> > full IPv6 address instead of ::1, and it doesn't happen if you don't
> > set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > I tried on an ARM system and x86_64.
> >
> > I haven't dug into the kernel to see if I could find anything yet, but I
> > thought I would go ahead and report it.  I am attaching a reproducer.
> > Basically, compile the following code:
> The code only set IPV6_V6ONLY on server side, so the client side will
> still bind all the local ipv4 addresses (as you didn't call bind() to
> bind any specific addresses ). Then after the connection is created,
> the client will send HB on the v4 paths to the server. The server
> will abort the connection, as it can't support v4.
> 
> So you can work around it by either:
> 
>   - set IPV6_V6ONLY on client side.
> 
> or
> 
>   - bind to the specific v6 addresses on the client side.
> 
> I don't see RFC said something about this.
> So it may not be a good idea to change the current behaviour
> to not establish the connection in this case, which may cause regression.

Ok, I understand this.  It's a little strange, but I see why it works
this way.

Thanks,

-corey

> 
> >
> >   gcc -g -o sctptest -Wall sctptest.c
> >
> > and run it in one window as a server:
> >
> >   ./sctptest a
> >
> > (Pass in any option to be the server) and run the following in another
> > window as the client:
> >
> >   ./sctptest
> >
> > It disconnects after about 2.5 seconds.  If it works, it should just sit
> > there forever.
> >
> > -corey
> >
> >
> > #include <stdio.h>
> > #include <stdbool.h>
> > #include <string.h>
> > #include <unistd.h>
> > #include <fcntl.h>
> > #include <sys/select.h>
> > #include <arpa/inet.h>
> > #include <netinet/sctp.h>
> > #include <sys/types.h>
> > #include <sys/socket.h>
> > #include <netdb.h>
> >
> > static int
> > getaddr(const char *addr, const char *port, bool listen,
> >         struct addrinfo **rai)
> > {
> >     struct addrinfo *ai, hints;
> >
> >     memset(&hints, 0, sizeof(hints));
> >     hints.ai_flags = AI_ADDRCONFIG;
> >     if (listen)
> >         hints.ai_flags |= AI_PASSIVE;
> >     hints.ai_family = AF_UNSPEC;
> >     hints.ai_socktype = SOCK_STREAM;
> >     hints.ai_protocol = IPPROTO_SCTP;
> >     if (getaddrinfo(addr, port, &hints, &ai)) {
> >         perror("getaddrinfo");
> >         return -1;
> >     }
> >
> >     *rai = ai;
> >     return 0;
> > }
> >
> > static int
> > waitread(int s)
> > {
> >     char data[1];
> >     ssize_t rv;
> >
> >     rv = read(s, data, sizeof(data));
> >     if (rv == -1) {
> >         perror("read");
> >         return -1;
> >     }
> >     printf("Read %d bytes\n", (int) rv);
> >     return 0;
> > }
> >
> > static int
> > do_server(void)
> > {
> >     int err, ls, s, optval;
> >     struct addrinfo *ai;
> >
> >     printf("Server\n");
> >
> >     err = getaddr("::", "3023", true, &ai);
> >     if (err)
> >         return err;
> >
> >     ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >     if (ls == -1) {
> >         perror("socket");
> >         return -1;
> >     }
> >
> >     optval = 1;
> >     if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >                    (void *)&optval, sizeof(optval)) == -1) {
> >         perror("setsockopt reuseaddr");
> >         return -1;
> >     }
> >
> >     /* Comment this out and it will work. */
> >     if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >                    sizeof(optval)) == -1) {
> >         perror("setsockopt ipv6 only");
> >         return -1;
> >     }
> >
> >     err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >     if (err == -1) {
> >         perror("bind");
> >         return -1;
> >     }
> >
> >     err = listen(ls, 5);
> >     if (err == -1) {
> >         perror("listen");
> >         return -1;
> >     }
> >
> >     s = accept(ls, NULL, NULL);
> >     if (s == -1) {
> >         perror("accept");
> >         return -1;
> >     }
> >
> >     close(ls);
> >
> >     err = waitread(s);
> >     close(s);
> >     return err;
> > }
> >
> > static int
> > do_client(void)
> > {
> >     int err, s;
> >     struct addrinfo *ai;
> >
> >     printf("Client\n");
> >
> >     err = getaddr("::1", "3023", false, &ai);
> >     if (err)
> >         return err;
> >
> >     s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >     if (s == -1) {
> >         perror("socket");
> >         return -1;
> >     }
> >
> >     err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >     if (err == -1) {
> >         perror("connect");
> >         return -1;
> >     }
> >
> >     err = waitread(s);
> >     close(s);
> >     return err;
> > }
> >
> > int
> > main(int argc, char *argv[])
> > {
> >     int err;
> >
> >     if (argc > 1)
> >         err = do_server();
> >     else
> >         err = do_client();
> >     return !!err;
> > }
> >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 16:57     ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-22 16:57 UTC (permalink / raw)
  To: Xin Long
  Cc: Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner, linux-sctp, LKML

On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >
> > I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > then I make a connection to it using ::1, the connection will drop after
> > 2.5 seconds with an ECONNRESET error.
> >
> > It only happens on SCTP, it doesn't have the issue if you connect to a
> > full IPv6 address instead of ::1, and it doesn't happen if you don't
> > set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > I tried on an ARM system and x86_64.
> >
> > I haven't dug into the kernel to see if I could find anything yet, but I
> > thought I would go ahead and report it.  I am attaching a reproducer.
> > Basically, compile the following code:
> The code only set IPV6_V6ONLY on server side, so the client side will
> still bind all the local ipv4 addresses (as you didn't call bind() to
> bind any specific addresses ). Then after the connection is created,
> the client will send HB on the v4 paths to the server. The server
> will abort the connection, as it can't support v4.
> 
> So you can work around it by either:
> 
>   - set IPV6_V6ONLY on client side.
> 
> or
> 
>   - bind to the specific v6 addresses on the client side.
> 
> I don't see RFC said something about this.
> So it may not be a good idea to change the current behaviour
> to not establish the connection in this case, which may cause regression.

Ok, I understand this.  It's a little strange, but I see why it works
this way.

Thanks,

-corey

> 
> >
> >   gcc -g -o sctptest -Wall sctptest.c
> >
> > and run it in one window as a server:
> >
> >   ./sctptest a
> >
> > (Pass in any option to be the server) and run the following in another
> > window as the client:
> >
> >   ./sctptest
> >
> > It disconnects after about 2.5 seconds.  If it works, it should just sit
> > there forever.
> >
> > -corey
> >
> >
> > #include <stdio.h>
> > #include <stdbool.h>
> > #include <string.h>
> > #include <unistd.h>
> > #include <fcntl.h>
> > #include <sys/select.h>
> > #include <arpa/inet.h>
> > #include <netinet/sctp.h>
> > #include <sys/types.h>
> > #include <sys/socket.h>
> > #include <netdb.h>
> >
> > static int
> > getaddr(const char *addr, const char *port, bool listen,
> >         struct addrinfo **rai)
> > {
> >     struct addrinfo *ai, hints;
> >
> >     memset(&hints, 0, sizeof(hints));
> >     hints.ai_flags = AI_ADDRCONFIG;
> >     if (listen)
> >         hints.ai_flags |= AI_PASSIVE;
> >     hints.ai_family = AF_UNSPEC;
> >     hints.ai_socktype = SOCK_STREAM;
> >     hints.ai_protocol = IPPROTO_SCTP;
> >     if (getaddrinfo(addr, port, &hints, &ai)) {
> >         perror("getaddrinfo");
> >         return -1;
> >     }
> >
> >     *rai = ai;
> >     return 0;
> > }
> >
> > static int
> > waitread(int s)
> > {
> >     char data[1];
> >     ssize_t rv;
> >
> >     rv = read(s, data, sizeof(data));
> >     if (rv = -1) {
> >         perror("read");
> >         return -1;
> >     }
> >     printf("Read %d bytes\n", (int) rv);
> >     return 0;
> > }
> >
> > static int
> > do_server(void)
> > {
> >     int err, ls, s, optval;
> >     struct addrinfo *ai;
> >
> >     printf("Server\n");
> >
> >     err = getaddr("::", "3023", true, &ai);
> >     if (err)
> >         return err;
> >
> >     ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >     if (ls = -1) {
> >         perror("socket");
> >         return -1;
> >     }
> >
> >     optval = 1;
> >     if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >                    (void *)&optval, sizeof(optval)) = -1) {
> >         perror("setsockopt reuseaddr");
> >         return -1;
> >     }
> >
> >     /* Comment this out and it will work. */
> >     if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >                    sizeof(optval)) = -1) {
> >         perror("setsockopt ipv6 only");
> >         return -1;
> >     }
> >
> >     err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >     if (err = -1) {
> >         perror("bind");
> >         return -1;
> >     }
> >
> >     err = listen(ls, 5);
> >     if (err = -1) {
> >         perror("listen");
> >         return -1;
> >     }
> >
> >     s = accept(ls, NULL, NULL);
> >     if (s = -1) {
> >         perror("accept");
> >         return -1;
> >     }
> >
> >     close(ls);
> >
> >     err = waitread(s);
> >     close(s);
> >     return err;
> > }
> >
> > static int
> > do_client(void)
> > {
> >     int err, s;
> >     struct addrinfo *ai;
> >
> >     printf("Client\n");
> >
> >     err = getaddr("::1", "3023", false, &ai);
> >     if (err)
> >         return err;
> >
> >     s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >     if (s = -1) {
> >         perror("socket");
> >         return -1;
> >     }
> >
> >     err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >     if (err = -1) {
> >         perror("connect");
> >         return -1;
> >     }
> >
> >     err = waitread(s);
> >     close(s);
> >     return err;
> > }
> >
> > int
> > main(int argc, char *argv[])
> > {
> >     int err;
> >
> >     if (argc > 1)
> >         err = do_server();
> >     else
> >         err = do_client();
> >     return !!err;
> > }
> >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 16:57     ` Corey Minyard
@ 2020-06-22 18:01       ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 18:01 UTC (permalink / raw)
  To: minyard
  Cc: Xin Long, Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner,
	linux-sctp, LKML

> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> 
> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>> 
>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>> then I make a connection to it using ::1, the connection will drop after
>>> 2.5 seconds with an ECONNRESET error.
>>> 
>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>> I tried on an ARM system and x86_64.
>>> 
>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>> Basically, compile the following code:
>> The code only set IPV6_V6ONLY on server side, so the client side will
>> still bind all the local ipv4 addresses (as you didn't call bind() to
>> bind any specific addresses ). Then after the connection is created,
>> the client will send HB on the v4 paths to the server. The server
>> will abort the connection, as it can't support v4.
>> 
>> So you can work around it by either:
>> 
>>  - set IPV6_V6ONLY on client side.
>> 
>> or
>> 
>>  - bind to the specific v6 addresses on the client side.
>> 
>> I don't see RFC said something about this.
>> So it may not be a good idea to change the current behaviour
>> to not establish the connection in this case, which may cause regression.
> 
> Ok, I understand this.  It's a little strange, but I see why it works
> this way.
I don't. I would expect it to work as I described in my email.
Could someone explain me how and why it is behaving different from
my expectation?

Best regards
Michael
> 
> Thanks,
> 
> -corey
> 
>> 
>>> 
>>>  gcc -g -o sctptest -Wall sctptest.c
>>> 
>>> and run it in one window as a server:
>>> 
>>>  ./sctptest a
>>> 
>>> (Pass in any option to be the server) and run the following in another
>>> window as the client:
>>> 
>>>  ./sctptest
>>> 
>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>>> there forever.
>>> 
>>> -corey
>>> 
>>> 
>>> #include <stdio.h>
>>> #include <stdbool.h>
>>> #include <string.h>
>>> #include <unistd.h>
>>> #include <fcntl.h>
>>> #include <sys/select.h>
>>> #include <arpa/inet.h>
>>> #include <netinet/sctp.h>
>>> #include <sys/types.h>
>>> #include <sys/socket.h>
>>> #include <netdb.h>
>>> 
>>> static int
>>> getaddr(const char *addr, const char *port, bool listen,
>>>        struct addrinfo **rai)
>>> {
>>>    struct addrinfo *ai, hints;
>>> 
>>>    memset(&hints, 0, sizeof(hints));
>>>    hints.ai_flags = AI_ADDRCONFIG;
>>>    if (listen)
>>>        hints.ai_flags |= AI_PASSIVE;
>>>    hints.ai_family = AF_UNSPEC;
>>>    hints.ai_socktype = SOCK_STREAM;
>>>    hints.ai_protocol = IPPROTO_SCTP;
>>>    if (getaddrinfo(addr, port, &hints, &ai)) {
>>>        perror("getaddrinfo");
>>>        return -1;
>>>    }
>>> 
>>>    *rai = ai;
>>>    return 0;
>>> }
>>> 
>>> static int
>>> waitread(int s)
>>> {
>>>    char data[1];
>>>    ssize_t rv;
>>> 
>>>    rv = read(s, data, sizeof(data));
>>>    if (rv == -1) {
>>>        perror("read");
>>>        return -1;
>>>    }
>>>    printf("Read %d bytes\n", (int) rv);
>>>    return 0;
>>> }
>>> 
>>> static int
>>> do_server(void)
>>> {
>>>    int err, ls, s, optval;
>>>    struct addrinfo *ai;
>>> 
>>>    printf("Server\n");
>>> 
>>>    err = getaddr("::", "3023", true, &ai);
>>>    if (err)
>>>        return err;
>>> 
>>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>    if (ls == -1) {
>>>        perror("socket");
>>>        return -1;
>>>    }
>>> 
>>>    optval = 1;
>>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>>                   (void *)&optval, sizeof(optval)) == -1) {
>>>        perror("setsockopt reuseaddr");
>>>        return -1;
>>>    }
>>> 
>>>    /* Comment this out and it will work. */
>>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>>                   sizeof(optval)) == -1) {
>>>        perror("setsockopt ipv6 only");
>>>        return -1;
>>>    }
>>> 
>>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>>    if (err == -1) {
>>>        perror("bind");
>>>        return -1;
>>>    }
>>> 
>>>    err = listen(ls, 5);
>>>    if (err == -1) {
>>>        perror("listen");
>>>        return -1;
>>>    }
>>> 
>>>    s = accept(ls, NULL, NULL);
>>>    if (s == -1) {
>>>        perror("accept");
>>>        return -1;
>>>    }
>>> 
>>>    close(ls);
>>> 
>>>    err = waitread(s);
>>>    close(s);
>>>    return err;
>>> }
>>> 
>>> static int
>>> do_client(void)
>>> {
>>>    int err, s;
>>>    struct addrinfo *ai;
>>> 
>>>    printf("Client\n");
>>> 
>>>    err = getaddr("::1", "3023", false, &ai);
>>>    if (err)
>>>        return err;
>>> 
>>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>    if (s == -1) {
>>>        perror("socket");
>>>        return -1;
>>>    }
>>> 
>>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>>    if (err == -1) {
>>>        perror("connect");
>>>        return -1;
>>>    }
>>> 
>>>    err = waitread(s);
>>>    close(s);
>>>    return err;
>>> }
>>> 
>>> int
>>> main(int argc, char *argv[])
>>> {
>>>    int err;
>>> 
>>>    if (argc > 1)
>>>        err = do_server();
>>>    else
>>>        err = do_client();
>>>    return !!err;
>>> }
>>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 18:01       ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 18:01 UTC (permalink / raw)
  To: minyard
  Cc: Xin Long, Vlad Yasevich, Neil Horman, Marcelo Ricardo Leitner,
	linux-sctp, LKML

> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> 
> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>> 
>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>> then I make a connection to it using ::1, the connection will drop after
>>> 2.5 seconds with an ECONNRESET error.
>>> 
>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>> I tried on an ARM system and x86_64.
>>> 
>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>> Basically, compile the following code:
>> The code only set IPV6_V6ONLY on server side, so the client side will
>> still bind all the local ipv4 addresses (as you didn't call bind() to
>> bind any specific addresses ). Then after the connection is created,
>> the client will send HB on the v4 paths to the server. The server
>> will abort the connection, as it can't support v4.
>> 
>> So you can work around it by either:
>> 
>>  - set IPV6_V6ONLY on client side.
>> 
>> or
>> 
>>  - bind to the specific v6 addresses on the client side.
>> 
>> I don't see RFC said something about this.
>> So it may not be a good idea to change the current behaviour
>> to not establish the connection in this case, which may cause regression.
> 
> Ok, I understand this.  It's a little strange, but I see why it works
> this way.
I don't. I would expect it to work as I described in my email.
Could someone explain me how and why it is behaving different from
my expectation?

Best regards
Michael
> 
> Thanks,
> 
> -corey
> 
>> 
>>> 
>>>  gcc -g -o sctptest -Wall sctptest.c
>>> 
>>> and run it in one window as a server:
>>> 
>>>  ./sctptest a
>>> 
>>> (Pass in any option to be the server) and run the following in another
>>> window as the client:
>>> 
>>>  ./sctptest
>>> 
>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>>> there forever.
>>> 
>>> -corey
>>> 
>>> 
>>> #include <stdio.h>
>>> #include <stdbool.h>
>>> #include <string.h>
>>> #include <unistd.h>
>>> #include <fcntl.h>
>>> #include <sys/select.h>
>>> #include <arpa/inet.h>
>>> #include <netinet/sctp.h>
>>> #include <sys/types.h>
>>> #include <sys/socket.h>
>>> #include <netdb.h>
>>> 
>>> static int
>>> getaddr(const char *addr, const char *port, bool listen,
>>>        struct addrinfo **rai)
>>> {
>>>    struct addrinfo *ai, hints;
>>> 
>>>    memset(&hints, 0, sizeof(hints));
>>>    hints.ai_flags = AI_ADDRCONFIG;
>>>    if (listen)
>>>        hints.ai_flags |= AI_PASSIVE;
>>>    hints.ai_family = AF_UNSPEC;
>>>    hints.ai_socktype = SOCK_STREAM;
>>>    hints.ai_protocol = IPPROTO_SCTP;
>>>    if (getaddrinfo(addr, port, &hints, &ai)) {
>>>        perror("getaddrinfo");
>>>        return -1;
>>>    }
>>> 
>>>    *rai = ai;
>>>    return 0;
>>> }
>>> 
>>> static int
>>> waitread(int s)
>>> {
>>>    char data[1];
>>>    ssize_t rv;
>>> 
>>>    rv = read(s, data, sizeof(data));
>>>    if (rv = -1) {
>>>        perror("read");
>>>        return -1;
>>>    }
>>>    printf("Read %d bytes\n", (int) rv);
>>>    return 0;
>>> }
>>> 
>>> static int
>>> do_server(void)
>>> {
>>>    int err, ls, s, optval;
>>>    struct addrinfo *ai;
>>> 
>>>    printf("Server\n");
>>> 
>>>    err = getaddr("::", "3023", true, &ai);
>>>    if (err)
>>>        return err;
>>> 
>>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>    if (ls = -1) {
>>>        perror("socket");
>>>        return -1;
>>>    }
>>> 
>>>    optval = 1;
>>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>>                   (void *)&optval, sizeof(optval)) = -1) {
>>>        perror("setsockopt reuseaddr");
>>>        return -1;
>>>    }
>>> 
>>>    /* Comment this out and it will work. */
>>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>>                   sizeof(optval)) = -1) {
>>>        perror("setsockopt ipv6 only");
>>>        return -1;
>>>    }
>>> 
>>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>>    if (err = -1) {
>>>        perror("bind");
>>>        return -1;
>>>    }
>>> 
>>>    err = listen(ls, 5);
>>>    if (err = -1) {
>>>        perror("listen");
>>>        return -1;
>>>    }
>>> 
>>>    s = accept(ls, NULL, NULL);
>>>    if (s = -1) {
>>>        perror("accept");
>>>        return -1;
>>>    }
>>> 
>>>    close(ls);
>>> 
>>>    err = waitread(s);
>>>    close(s);
>>>    return err;
>>> }
>>> 
>>> static int
>>> do_client(void)
>>> {
>>>    int err, s;
>>>    struct addrinfo *ai;
>>> 
>>>    printf("Client\n");
>>> 
>>>    err = getaddr("::1", "3023", false, &ai);
>>>    if (err)
>>>        return err;
>>> 
>>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>    if (s = -1) {
>>>        perror("socket");
>>>        return -1;
>>>    }
>>> 
>>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>>    if (err = -1) {
>>>        perror("connect");
>>>        return -1;
>>>    }
>>> 
>>>    err = waitread(s);
>>>    close(s);
>>>    return err;
>>> }
>>> 
>>> int
>>> main(int argc, char *argv[])
>>> {
>>>    int err;
>>> 
>>>    if (argc > 1)
>>>        err = do_server();
>>>    else
>>>        err = do_client();
>>>    return !!err;
>>> }
>>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 18:01       ` Michael Tuexen
@ 2020-06-22 18:32         ` Marcelo Ricardo Leitner
  -1 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-22 18:32 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: minyard, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp, LKML

On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > 
> > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>> 
> >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>> then I make a connection to it using ::1, the connection will drop after
> >>> 2.5 seconds with an ECONNRESET error.
> >>> 
> >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>> I tried on an ARM system and x86_64.
> >>> 
> >>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>> Basically, compile the following code:
> >> The code only set IPV6_V6ONLY on server side, so the client side will
> >> still bind all the local ipv4 addresses (as you didn't call bind() to
> >> bind any specific addresses ). Then after the connection is created,
> >> the client will send HB on the v4 paths to the server. The server
> >> will abort the connection, as it can't support v4.
> >> 
> >> So you can work around it by either:
> >> 
> >>  - set IPV6_V6ONLY on client side.
> >> 
> >> or
> >> 
> >>  - bind to the specific v6 addresses on the client side.
> >> 
> >> I don't see RFC said something about this.
> >> So it may not be a good idea to change the current behaviour
> >> to not establish the connection in this case, which may cause regression.
> > 
> > Ok, I understand this.  It's a little strange, but I see why it works
> > this way.
> I don't. I would expect it to work as I described in my email.
> Could someone explain me how and why it is behaving different from
> my expectation?

It looks like a bug to me. Testing with this test app here, I can see
the INIT_ACK being sent with a bunch of ipv4 addresses in it and
that's unexpected for a v6only socket. As is, it's the server saying
"I'm available at these other addresses too, but not."

Thanks,
Marcelo

> 
> Best regards
> Michael
> > 
> > Thanks,
> > 
> > -corey
> > 
> >> 
> >>> 
> >>>  gcc -g -o sctptest -Wall sctptest.c
> >>> 
> >>> and run it in one window as a server:
> >>> 
> >>>  ./sctptest a
> >>> 
> >>> (Pass in any option to be the server) and run the following in another
> >>> window as the client:
> >>> 
> >>>  ./sctptest
> >>> 
> >>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> >>> there forever.
> >>> 
> >>> -corey
> >>> 
> >>> 
> >>> #include <stdio.h>
> >>> #include <stdbool.h>
> >>> #include <string.h>
> >>> #include <unistd.h>
> >>> #include <fcntl.h>
> >>> #include <sys/select.h>
> >>> #include <arpa/inet.h>
> >>> #include <netinet/sctp.h>
> >>> #include <sys/types.h>
> >>> #include <sys/socket.h>
> >>> #include <netdb.h>
> >>> 
> >>> static int
> >>> getaddr(const char *addr, const char *port, bool listen,
> >>>        struct addrinfo **rai)
> >>> {
> >>>    struct addrinfo *ai, hints;
> >>> 
> >>>    memset(&hints, 0, sizeof(hints));
> >>>    hints.ai_flags = AI_ADDRCONFIG;
> >>>    if (listen)
> >>>        hints.ai_flags |= AI_PASSIVE;
> >>>    hints.ai_family = AF_UNSPEC;
> >>>    hints.ai_socktype = SOCK_STREAM;
> >>>    hints.ai_protocol = IPPROTO_SCTP;
> >>>    if (getaddrinfo(addr, port, &hints, &ai)) {
> >>>        perror("getaddrinfo");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    *rai = ai;
> >>>    return 0;
> >>> }
> >>> 
> >>> static int
> >>> waitread(int s)
> >>> {
> >>>    char data[1];
> >>>    ssize_t rv;
> >>> 
> >>>    rv = read(s, data, sizeof(data));
> >>>    if (rv == -1) {
> >>>        perror("read");
> >>>        return -1;
> >>>    }
> >>>    printf("Read %d bytes\n", (int) rv);
> >>>    return 0;
> >>> }
> >>> 
> >>> static int
> >>> do_server(void)
> >>> {
> >>>    int err, ls, s, optval;
> >>>    struct addrinfo *ai;
> >>> 
> >>>    printf("Server\n");
> >>> 
> >>>    err = getaddr("::", "3023", true, &ai);
> >>>    if (err)
> >>>        return err;
> >>> 
> >>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>    if (ls == -1) {
> >>>        perror("socket");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    optval = 1;
> >>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >>>                   (void *)&optval, sizeof(optval)) == -1) {
> >>>        perror("setsockopt reuseaddr");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    /* Comment this out and it will work. */
> >>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >>>                   sizeof(optval)) == -1) {
> >>>        perror("setsockopt ipv6 only");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >>>    if (err == -1) {
> >>>        perror("bind");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = listen(ls, 5);
> >>>    if (err == -1) {
> >>>        perror("listen");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    s = accept(ls, NULL, NULL);
> >>>    if (s == -1) {
> >>>        perror("accept");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    close(ls);
> >>> 
> >>>    err = waitread(s);
> >>>    close(s);
> >>>    return err;
> >>> }
> >>> 
> >>> static int
> >>> do_client(void)
> >>> {
> >>>    int err, s;
> >>>    struct addrinfo *ai;
> >>> 
> >>>    printf("Client\n");
> >>> 
> >>>    err = getaddr("::1", "3023", false, &ai);
> >>>    if (err)
> >>>        return err;
> >>> 
> >>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>    if (s == -1) {
> >>>        perror("socket");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >>>    if (err == -1) {
> >>>        perror("connect");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = waitread(s);
> >>>    close(s);
> >>>    return err;
> >>> }
> >>> 
> >>> int
> >>> main(int argc, char *argv[])
> >>> {
> >>>    int err;
> >>> 
> >>>    if (argc > 1)
> >>>        err = do_server();
> >>>    else
> >>>        err = do_client();
> >>>    return !!err;
> >>> }
> >>> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 18:32         ` Marcelo Ricardo Leitner
  0 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-22 18:32 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: minyard, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp, LKML

On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > 
> > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>> 
> >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>> then I make a connection to it using ::1, the connection will drop after
> >>> 2.5 seconds with an ECONNRESET error.
> >>> 
> >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>> I tried on an ARM system and x86_64.
> >>> 
> >>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>> Basically, compile the following code:
> >> The code only set IPV6_V6ONLY on server side, so the client side will
> >> still bind all the local ipv4 addresses (as you didn't call bind() to
> >> bind any specific addresses ). Then after the connection is created,
> >> the client will send HB on the v4 paths to the server. The server
> >> will abort the connection, as it can't support v4.
> >> 
> >> So you can work around it by either:
> >> 
> >>  - set IPV6_V6ONLY on client side.
> >> 
> >> or
> >> 
> >>  - bind to the specific v6 addresses on the client side.
> >> 
> >> I don't see RFC said something about this.
> >> So it may not be a good idea to change the current behaviour
> >> to not establish the connection in this case, which may cause regression.
> > 
> > Ok, I understand this.  It's a little strange, but I see why it works
> > this way.
> I don't. I would expect it to work as I described in my email.
> Could someone explain me how and why it is behaving different from
> my expectation?

It looks like a bug to me. Testing with this test app here, I can see
the INIT_ACK being sent with a bunch of ipv4 addresses in it and
that's unexpected for a v6only socket. As is, it's the server saying
"I'm available at these other addresses too, but not."

Thanks,
Marcelo

> 
> Best regards
> Michael
> > 
> > Thanks,
> > 
> > -corey
> > 
> >> 
> >>> 
> >>>  gcc -g -o sctptest -Wall sctptest.c
> >>> 
> >>> and run it in one window as a server:
> >>> 
> >>>  ./sctptest a
> >>> 
> >>> (Pass in any option to be the server) and run the following in another
> >>> window as the client:
> >>> 
> >>>  ./sctptest
> >>> 
> >>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> >>> there forever.
> >>> 
> >>> -corey
> >>> 
> >>> 
> >>> #include <stdio.h>
> >>> #include <stdbool.h>
> >>> #include <string.h>
> >>> #include <unistd.h>
> >>> #include <fcntl.h>
> >>> #include <sys/select.h>
> >>> #include <arpa/inet.h>
> >>> #include <netinet/sctp.h>
> >>> #include <sys/types.h>
> >>> #include <sys/socket.h>
> >>> #include <netdb.h>
> >>> 
> >>> static int
> >>> getaddr(const char *addr, const char *port, bool listen,
> >>>        struct addrinfo **rai)
> >>> {
> >>>    struct addrinfo *ai, hints;
> >>> 
> >>>    memset(&hints, 0, sizeof(hints));
> >>>    hints.ai_flags = AI_ADDRCONFIG;
> >>>    if (listen)
> >>>        hints.ai_flags |= AI_PASSIVE;
> >>>    hints.ai_family = AF_UNSPEC;
> >>>    hints.ai_socktype = SOCK_STREAM;
> >>>    hints.ai_protocol = IPPROTO_SCTP;
> >>>    if (getaddrinfo(addr, port, &hints, &ai)) {
> >>>        perror("getaddrinfo");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    *rai = ai;
> >>>    return 0;
> >>> }
> >>> 
> >>> static int
> >>> waitread(int s)
> >>> {
> >>>    char data[1];
> >>>    ssize_t rv;
> >>> 
> >>>    rv = read(s, data, sizeof(data));
> >>>    if (rv = -1) {
> >>>        perror("read");
> >>>        return -1;
> >>>    }
> >>>    printf("Read %d bytes\n", (int) rv);
> >>>    return 0;
> >>> }
> >>> 
> >>> static int
> >>> do_server(void)
> >>> {
> >>>    int err, ls, s, optval;
> >>>    struct addrinfo *ai;
> >>> 
> >>>    printf("Server\n");
> >>> 
> >>>    err = getaddr("::", "3023", true, &ai);
> >>>    if (err)
> >>>        return err;
> >>> 
> >>>    ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>    if (ls = -1) {
> >>>        perror("socket");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    optval = 1;
> >>>    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >>>                   (void *)&optval, sizeof(optval)) = -1) {
> >>>        perror("setsockopt reuseaddr");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    /* Comment this out and it will work. */
> >>>    if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >>>                   sizeof(optval)) = -1) {
> >>>        perror("setsockopt ipv6 only");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >>>    if (err = -1) {
> >>>        perror("bind");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = listen(ls, 5);
> >>>    if (err = -1) {
> >>>        perror("listen");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    s = accept(ls, NULL, NULL);
> >>>    if (s = -1) {
> >>>        perror("accept");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    close(ls);
> >>> 
> >>>    err = waitread(s);
> >>>    close(s);
> >>>    return err;
> >>> }
> >>> 
> >>> static int
> >>> do_client(void)
> >>> {
> >>>    int err, s;
> >>>    struct addrinfo *ai;
> >>> 
> >>>    printf("Client\n");
> >>> 
> >>>    err = getaddr("::1", "3023", false, &ai);
> >>>    if (err)
> >>>        return err;
> >>> 
> >>>    s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>    if (s = -1) {
> >>>        perror("socket");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >>>    if (err = -1) {
> >>>        perror("connect");
> >>>        return -1;
> >>>    }
> >>> 
> >>>    err = waitread(s);
> >>>    close(s);
> >>>    return err;
> >>> }
> >>> 
> >>> int
> >>> main(int argc, char *argv[])
> >>> {
> >>>    int err;
> >>> 
> >>>    if (argc > 1)
> >>>        err = do_server();
> >>>    else
> >>>        err = do_client();
> >>>    return !!err;
> >>> }
> >>> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 18:32         ` Marcelo Ricardo Leitner
@ 2020-06-22 18:34           ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 18:34 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: minyard, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp, LKML

> On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>> 
>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>> 
>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>> 2.5 seconds with an ECONNRESET error.
>>>>> 
>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>> I tried on an ARM system and x86_64.
>>>>> 
>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>> Basically, compile the following code:
>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>> bind any specific addresses ). Then after the connection is created,
>>>> the client will send HB on the v4 paths to the server. The server
>>>> will abort the connection, as it can't support v4.
>>>> 
>>>> So you can work around it by either:
>>>> 
>>>> - set IPV6_V6ONLY on client side.
>>>> 
>>>> or
>>>> 
>>>> - bind to the specific v6 addresses on the client side.
>>>> 
>>>> I don't see RFC said something about this.
>>>> So it may not be a good idea to change the current behaviour
>>>> to not establish the connection in this case, which may cause regression.
>>> 
>>> Ok, I understand this.  It's a little strange, but I see why it works
>>> this way.
>> I don't. I would expect it to work as I described in my email.
>> Could someone explain me how and why it is behaving different from
>> my expectation?
> 
> It looks like a bug to me. Testing with this test app here, I can see
> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> that's unexpected for a v6only socket. As is, it's the server saying
> "I'm available at these other addresses too, but not."
I agree.

Best regards
Michael
> 
> Thanks,
> Marcelo
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Thanks,
>>> 
>>> -corey
>>> 
>>>> 
>>>>> 
>>>>> gcc -g -o sctptest -Wall sctptest.c
>>>>> 
>>>>> and run it in one window as a server:
>>>>> 
>>>>> ./sctptest a
>>>>> 
>>>>> (Pass in any option to be the server) and run the following in another
>>>>> window as the client:
>>>>> 
>>>>> ./sctptest
>>>>> 
>>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>>>>> there forever.
>>>>> 
>>>>> -corey
>>>>> 
>>>>> 
>>>>> #include <stdio.h>
>>>>> #include <stdbool.h>
>>>>> #include <string.h>
>>>>> #include <unistd.h>
>>>>> #include <fcntl.h>
>>>>> #include <sys/select.h>
>>>>> #include <arpa/inet.h>
>>>>> #include <netinet/sctp.h>
>>>>> #include <sys/types.h>
>>>>> #include <sys/socket.h>
>>>>> #include <netdb.h>
>>>>> 
>>>>> static int
>>>>> getaddr(const char *addr, const char *port, bool listen,
>>>>>       struct addrinfo **rai)
>>>>> {
>>>>>   struct addrinfo *ai, hints;
>>>>> 
>>>>>   memset(&hints, 0, sizeof(hints));
>>>>>   hints.ai_flags = AI_ADDRCONFIG;
>>>>>   if (listen)
>>>>>       hints.ai_flags |= AI_PASSIVE;
>>>>>   hints.ai_family = AF_UNSPEC;
>>>>>   hints.ai_socktype = SOCK_STREAM;
>>>>>   hints.ai_protocol = IPPROTO_SCTP;
>>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
>>>>>       perror("getaddrinfo");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   *rai = ai;
>>>>>   return 0;
>>>>> }
>>>>> 
>>>>> static int
>>>>> waitread(int s)
>>>>> {
>>>>>   char data[1];
>>>>>   ssize_t rv;
>>>>> 
>>>>>   rv = read(s, data, sizeof(data));
>>>>>   if (rv == -1) {
>>>>>       perror("read");
>>>>>       return -1;
>>>>>   }
>>>>>   printf("Read %d bytes\n", (int) rv);
>>>>>   return 0;
>>>>> }
>>>>> 
>>>>> static int
>>>>> do_server(void)
>>>>> {
>>>>>   int err, ls, s, optval;
>>>>>   struct addrinfo *ai;
>>>>> 
>>>>>   printf("Server\n");
>>>>> 
>>>>>   err = getaddr("::", "3023", true, &ai);
>>>>>   if (err)
>>>>>       return err;
>>>>> 
>>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>>>   if (ls == -1) {
>>>>>       perror("socket");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   optval = 1;
>>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>>>>                  (void *)&optval, sizeof(optval)) == -1) {
>>>>>       perror("setsockopt reuseaddr");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   /* Comment this out and it will work. */
>>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>>>>                  sizeof(optval)) == -1) {
>>>>>       perror("setsockopt ipv6 only");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>>>>   if (err == -1) {
>>>>>       perror("bind");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = listen(ls, 5);
>>>>>   if (err == -1) {
>>>>>       perror("listen");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   s = accept(ls, NULL, NULL);
>>>>>   if (s == -1) {
>>>>>       perror("accept");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   close(ls);
>>>>> 
>>>>>   err = waitread(s);
>>>>>   close(s);
>>>>>   return err;
>>>>> }
>>>>> 
>>>>> static int
>>>>> do_client(void)
>>>>> {
>>>>>   int err, s;
>>>>>   struct addrinfo *ai;
>>>>> 
>>>>>   printf("Client\n");
>>>>> 
>>>>>   err = getaddr("::1", "3023", false, &ai);
>>>>>   if (err)
>>>>>       return err;
>>>>> 
>>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>>>   if (s == -1) {
>>>>>       perror("socket");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>>>>   if (err == -1) {
>>>>>       perror("connect");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = waitread(s);
>>>>>   close(s);
>>>>>   return err;
>>>>> }
>>>>> 
>>>>> int
>>>>> main(int argc, char *argv[])
>>>>> {
>>>>>   int err;
>>>>> 
>>>>>   if (argc > 1)
>>>>>       err = do_server();
>>>>>   else
>>>>>       err = do_client();
>>>>>   return !!err;
>>>>> }
>>>>> 
>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-22 18:34           ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-22 18:34 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: minyard, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp, LKML

> On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>> 
>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>> 
>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>> 2.5 seconds with an ECONNRESET error.
>>>>> 
>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>> I tried on an ARM system and x86_64.
>>>>> 
>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>> Basically, compile the following code:
>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>> bind any specific addresses ). Then after the connection is created,
>>>> the client will send HB on the v4 paths to the server. The server
>>>> will abort the connection, as it can't support v4.
>>>> 
>>>> So you can work around it by either:
>>>> 
>>>> - set IPV6_V6ONLY on client side.
>>>> 
>>>> or
>>>> 
>>>> - bind to the specific v6 addresses on the client side.
>>>> 
>>>> I don't see RFC said something about this.
>>>> So it may not be a good idea to change the current behaviour
>>>> to not establish the connection in this case, which may cause regression.
>>> 
>>> Ok, I understand this.  It's a little strange, but I see why it works
>>> this way.
>> I don't. I would expect it to work as I described in my email.
>> Could someone explain me how and why it is behaving different from
>> my expectation?
> 
> It looks like a bug to me. Testing with this test app here, I can see
> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> that's unexpected for a v6only socket. As is, it's the server saying
> "I'm available at these other addresses too, but not."
I agree.

Best regards
Michael
> 
> Thanks,
> Marcelo
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Thanks,
>>> 
>>> -corey
>>> 
>>>> 
>>>>> 
>>>>> gcc -g -o sctptest -Wall sctptest.c
>>>>> 
>>>>> and run it in one window as a server:
>>>>> 
>>>>> ./sctptest a
>>>>> 
>>>>> (Pass in any option to be the server) and run the following in another
>>>>> window as the client:
>>>>> 
>>>>> ./sctptest
>>>>> 
>>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
>>>>> there forever.
>>>>> 
>>>>> -corey
>>>>> 
>>>>> 
>>>>> #include <stdio.h>
>>>>> #include <stdbool.h>
>>>>> #include <string.h>
>>>>> #include <unistd.h>
>>>>> #include <fcntl.h>
>>>>> #include <sys/select.h>
>>>>> #include <arpa/inet.h>
>>>>> #include <netinet/sctp.h>
>>>>> #include <sys/types.h>
>>>>> #include <sys/socket.h>
>>>>> #include <netdb.h>
>>>>> 
>>>>> static int
>>>>> getaddr(const char *addr, const char *port, bool listen,
>>>>>       struct addrinfo **rai)
>>>>> {
>>>>>   struct addrinfo *ai, hints;
>>>>> 
>>>>>   memset(&hints, 0, sizeof(hints));
>>>>>   hints.ai_flags = AI_ADDRCONFIG;
>>>>>   if (listen)
>>>>>       hints.ai_flags |= AI_PASSIVE;
>>>>>   hints.ai_family = AF_UNSPEC;
>>>>>   hints.ai_socktype = SOCK_STREAM;
>>>>>   hints.ai_protocol = IPPROTO_SCTP;
>>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
>>>>>       perror("getaddrinfo");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   *rai = ai;
>>>>>   return 0;
>>>>> }
>>>>> 
>>>>> static int
>>>>> waitread(int s)
>>>>> {
>>>>>   char data[1];
>>>>>   ssize_t rv;
>>>>> 
>>>>>   rv = read(s, data, sizeof(data));
>>>>>   if (rv = -1) {
>>>>>       perror("read");
>>>>>       return -1;
>>>>>   }
>>>>>   printf("Read %d bytes\n", (int) rv);
>>>>>   return 0;
>>>>> }
>>>>> 
>>>>> static int
>>>>> do_server(void)
>>>>> {
>>>>>   int err, ls, s, optval;
>>>>>   struct addrinfo *ai;
>>>>> 
>>>>>   printf("Server\n");
>>>>> 
>>>>>   err = getaddr("::", "3023", true, &ai);
>>>>>   if (err)
>>>>>       return err;
>>>>> 
>>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>>>   if (ls = -1) {
>>>>>       perror("socket");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   optval = 1;
>>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
>>>>>                  (void *)&optval, sizeof(optval)) = -1) {
>>>>>       perror("setsockopt reuseaddr");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   /* Comment this out and it will work. */
>>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
>>>>>                  sizeof(optval)) = -1) {
>>>>>       perror("setsockopt ipv6 only");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
>>>>>   if (err = -1) {
>>>>>       perror("bind");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = listen(ls, 5);
>>>>>   if (err = -1) {
>>>>>       perror("listen");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   s = accept(ls, NULL, NULL);
>>>>>   if (s = -1) {
>>>>>       perror("accept");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   close(ls);
>>>>> 
>>>>>   err = waitread(s);
>>>>>   close(s);
>>>>>   return err;
>>>>> }
>>>>> 
>>>>> static int
>>>>> do_client(void)
>>>>> {
>>>>>   int err, s;
>>>>>   struct addrinfo *ai;
>>>>> 
>>>>>   printf("Client\n");
>>>>> 
>>>>>   err = getaddr("::1", "3023", false, &ai);
>>>>>   if (err)
>>>>>       return err;
>>>>> 
>>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
>>>>>   if (s = -1) {
>>>>>       perror("socket");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
>>>>>   if (err = -1) {
>>>>>       perror("connect");
>>>>>       return -1;
>>>>>   }
>>>>> 
>>>>>   err = waitread(s);
>>>>>   close(s);
>>>>>   return err;
>>>>> }
>>>>> 
>>>>> int
>>>>> main(int argc, char *argv[])
>>>>> {
>>>>>   int err;
>>>>> 
>>>>>   if (argc > 1)
>>>>>       err = do_server();
>>>>>   else
>>>>>       err = do_client();
>>>>>   return !!err;
>>>>> }
>>>>> 
>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-22 18:34           ` Michael Tuexen
@ 2020-06-23 10:13             ` Xin Long
  -1 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-23 10:13 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Marcelo Ricardo Leitner, minyard, Vlad Yasevich, Neil Horman,
	linux-sctp, LKML

On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
<Michael.Tuexen@lurchi.franken.de> wrote:
>
> > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >
> > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>
> >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>
> >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>
> >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>> I tried on an ARM system and x86_64.
> >>>>>
> >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>> Basically, compile the following code:
> >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>> bind any specific addresses ). Then after the connection is created,
> >>>> the client will send HB on the v4 paths to the server. The server
> >>>> will abort the connection, as it can't support v4.
> >>>>
> >>>> So you can work around it by either:
> >>>>
> >>>> - set IPV6_V6ONLY on client side.
> >>>>
> >>>> or
> >>>>
> >>>> - bind to the specific v6 addresses on the client side.
> >>>>
> >>>> I don't see RFC said something about this.
> >>>> So it may not be a good idea to change the current behaviour
> >>>> to not establish the connection in this case, which may cause regression.
> >>>
> >>> Ok, I understand this.  It's a little strange, but I see why it works
> >>> this way.
> >> I don't. I would expect it to work as I described in my email.
> >> Could someone explain me how and why it is behaving different from
> >> my expectation?
> >
> > It looks like a bug to me. Testing with this test app here, I can see
> > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > that's unexpected for a v6only socket. As is, it's the server saying
> > "I'm available at these other addresses too, but not."
> I agree.
Then we need a fix in sctp_bind_addrs_to_raw():

@@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
struct sctp_bind_addr *bp,
        addrparms = retval;

        list_for_each_entry(addr, &bp->address_list, list) {
+               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                af = sctp_get_af_specific(addr->a.v4.sin_family);
                len = af->to_addr_param(&addr->a, &rawaddr);
                memcpy(addrparms.v, &rawaddr, len);

>
> Best regards
> Michael
> >
> > Thanks,
> > Marcelo
> >
> >>
> >> Best regards
> >> Michael
> >>>
> >>> Thanks,
> >>>
> >>> -corey
> >>>
> >>>>
> >>>>>
> >>>>> gcc -g -o sctptest -Wall sctptest.c
> >>>>>
> >>>>> and run it in one window as a server:
> >>>>>
> >>>>> ./sctptest a
> >>>>>
> >>>>> (Pass in any option to be the server) and run the following in another
> >>>>> window as the client:
> >>>>>
> >>>>> ./sctptest
> >>>>>
> >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> >>>>> there forever.
> >>>>>
> >>>>> -corey
> >>>>>
> >>>>>
> >>>>> #include <stdio.h>
> >>>>> #include <stdbool.h>
> >>>>> #include <string.h>
> >>>>> #include <unistd.h>
> >>>>> #include <fcntl.h>
> >>>>> #include <sys/select.h>
> >>>>> #include <arpa/inet.h>
> >>>>> #include <netinet/sctp.h>
> >>>>> #include <sys/types.h>
> >>>>> #include <sys/socket.h>
> >>>>> #include <netdb.h>
> >>>>>
> >>>>> static int
> >>>>> getaddr(const char *addr, const char *port, bool listen,
> >>>>>       struct addrinfo **rai)
> >>>>> {
> >>>>>   struct addrinfo *ai, hints;
> >>>>>
> >>>>>   memset(&hints, 0, sizeof(hints));
> >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> >>>>>   if (listen)
> >>>>>       hints.ai_flags |= AI_PASSIVE;
> >>>>>   hints.ai_family = AF_UNSPEC;
> >>>>>   hints.ai_socktype = SOCK_STREAM;
> >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> >>>>>       perror("getaddrinfo");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   *rai = ai;
> >>>>>   return 0;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> waitread(int s)
> >>>>> {
> >>>>>   char data[1];
> >>>>>   ssize_t rv;
> >>>>>
> >>>>>   rv = read(s, data, sizeof(data));
> >>>>>   if (rv == -1) {
> >>>>>       perror("read");
> >>>>>       return -1;
> >>>>>   }
> >>>>>   printf("Read %d bytes\n", (int) rv);
> >>>>>   return 0;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> do_server(void)
> >>>>> {
> >>>>>   int err, ls, s, optval;
> >>>>>   struct addrinfo *ai;
> >>>>>
> >>>>>   printf("Server\n");
> >>>>>
> >>>>>   err = getaddr("::", "3023", true, &ai);
> >>>>>   if (err)
> >>>>>       return err;
> >>>>>
> >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>>>   if (ls == -1) {
> >>>>>       perror("socket");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   optval = 1;
> >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >>>>>                  (void *)&optval, sizeof(optval)) == -1) {
> >>>>>       perror("setsockopt reuseaddr");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   /* Comment this out and it will work. */
> >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >>>>>                  sizeof(optval)) == -1) {
> >>>>>       perror("setsockopt ipv6 only");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >>>>>   if (err == -1) {
> >>>>>       perror("bind");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = listen(ls, 5);
> >>>>>   if (err == -1) {
> >>>>>       perror("listen");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   s = accept(ls, NULL, NULL);
> >>>>>   if (s == -1) {
> >>>>>       perror("accept");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   close(ls);
> >>>>>
> >>>>>   err = waitread(s);
> >>>>>   close(s);
> >>>>>   return err;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> do_client(void)
> >>>>> {
> >>>>>   int err, s;
> >>>>>   struct addrinfo *ai;
> >>>>>
> >>>>>   printf("Client\n");
> >>>>>
> >>>>>   err = getaddr("::1", "3023", false, &ai);
> >>>>>   if (err)
> >>>>>       return err;
> >>>>>
> >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>>>   if (s == -1) {
> >>>>>       perror("socket");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >>>>>   if (err == -1) {
> >>>>>       perror("connect");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = waitread(s);
> >>>>>   close(s);
> >>>>>   return err;
> >>>>> }
> >>>>>
> >>>>> int
> >>>>> main(int argc, char *argv[])
> >>>>> {
> >>>>>   int err;
> >>>>>
> >>>>>   if (argc > 1)
> >>>>>       err = do_server();
> >>>>>   else
> >>>>>       err = do_client();
> >>>>>   return !!err;
> >>>>> }
> >>>>>
> >>
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 10:13             ` Xin Long
  0 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-23 10:13 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Marcelo Ricardo Leitner, minyard, Vlad Yasevich, Neil Horman,
	linux-sctp, LKML

On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
<Michael.Tuexen@lurchi.franken.de> wrote:
>
> > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >
> > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>
> >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>
> >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>
> >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>> I tried on an ARM system and x86_64.
> >>>>>
> >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>> Basically, compile the following code:
> >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>> bind any specific addresses ). Then after the connection is created,
> >>>> the client will send HB on the v4 paths to the server. The server
> >>>> will abort the connection, as it can't support v4.
> >>>>
> >>>> So you can work around it by either:
> >>>>
> >>>> - set IPV6_V6ONLY on client side.
> >>>>
> >>>> or
> >>>>
> >>>> - bind to the specific v6 addresses on the client side.
> >>>>
> >>>> I don't see RFC said something about this.
> >>>> So it may not be a good idea to change the current behaviour
> >>>> to not establish the connection in this case, which may cause regression.
> >>>
> >>> Ok, I understand this.  It's a little strange, but I see why it works
> >>> this way.
> >> I don't. I would expect it to work as I described in my email.
> >> Could someone explain me how and why it is behaving different from
> >> my expectation?
> >
> > It looks like a bug to me. Testing with this test app here, I can see
> > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > that's unexpected for a v6only socket. As is, it's the server saying
> > "I'm available at these other addresses too, but not."
> I agree.
Then we need a fix in sctp_bind_addrs_to_raw():

@@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
struct sctp_bind_addr *bp,
        addrparms = retval;

        list_for_each_entry(addr, &bp->address_list, list) {
+               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
+                   (AF_INET = addr->a.sa.sa_family))
+                       continue;
                af = sctp_get_af_specific(addr->a.v4.sin_family);
                len = af->to_addr_param(&addr->a, &rawaddr);
                memcpy(addrparms.v, &rawaddr, len);

>
> Best regards
> Michael
> >
> > Thanks,
> > Marcelo
> >
> >>
> >> Best regards
> >> Michael
> >>>
> >>> Thanks,
> >>>
> >>> -corey
> >>>
> >>>>
> >>>>>
> >>>>> gcc -g -o sctptest -Wall sctptest.c
> >>>>>
> >>>>> and run it in one window as a server:
> >>>>>
> >>>>> ./sctptest a
> >>>>>
> >>>>> (Pass in any option to be the server) and run the following in another
> >>>>> window as the client:
> >>>>>
> >>>>> ./sctptest
> >>>>>
> >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> >>>>> there forever.
> >>>>>
> >>>>> -corey
> >>>>>
> >>>>>
> >>>>> #include <stdio.h>
> >>>>> #include <stdbool.h>
> >>>>> #include <string.h>
> >>>>> #include <unistd.h>
> >>>>> #include <fcntl.h>
> >>>>> #include <sys/select.h>
> >>>>> #include <arpa/inet.h>
> >>>>> #include <netinet/sctp.h>
> >>>>> #include <sys/types.h>
> >>>>> #include <sys/socket.h>
> >>>>> #include <netdb.h>
> >>>>>
> >>>>> static int
> >>>>> getaddr(const char *addr, const char *port, bool listen,
> >>>>>       struct addrinfo **rai)
> >>>>> {
> >>>>>   struct addrinfo *ai, hints;
> >>>>>
> >>>>>   memset(&hints, 0, sizeof(hints));
> >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> >>>>>   if (listen)
> >>>>>       hints.ai_flags |= AI_PASSIVE;
> >>>>>   hints.ai_family = AF_UNSPEC;
> >>>>>   hints.ai_socktype = SOCK_STREAM;
> >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> >>>>>       perror("getaddrinfo");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   *rai = ai;
> >>>>>   return 0;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> waitread(int s)
> >>>>> {
> >>>>>   char data[1];
> >>>>>   ssize_t rv;
> >>>>>
> >>>>>   rv = read(s, data, sizeof(data));
> >>>>>   if (rv = -1) {
> >>>>>       perror("read");
> >>>>>       return -1;
> >>>>>   }
> >>>>>   printf("Read %d bytes\n", (int) rv);
> >>>>>   return 0;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> do_server(void)
> >>>>> {
> >>>>>   int err, ls, s, optval;
> >>>>>   struct addrinfo *ai;
> >>>>>
> >>>>>   printf("Server\n");
> >>>>>
> >>>>>   err = getaddr("::", "3023", true, &ai);
> >>>>>   if (err)
> >>>>>       return err;
> >>>>>
> >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>>>   if (ls = -1) {
> >>>>>       perror("socket");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   optval = 1;
> >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> >>>>>                  (void *)&optval, sizeof(optval)) = -1) {
> >>>>>       perror("setsockopt reuseaddr");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   /* Comment this out and it will work. */
> >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> >>>>>                  sizeof(optval)) = -1) {
> >>>>>       perror("setsockopt ipv6 only");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> >>>>>   if (err = -1) {
> >>>>>       perror("bind");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = listen(ls, 5);
> >>>>>   if (err = -1) {
> >>>>>       perror("listen");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   s = accept(ls, NULL, NULL);
> >>>>>   if (s = -1) {
> >>>>>       perror("accept");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   close(ls);
> >>>>>
> >>>>>   err = waitread(s);
> >>>>>   close(s);
> >>>>>   return err;
> >>>>> }
> >>>>>
> >>>>> static int
> >>>>> do_client(void)
> >>>>> {
> >>>>>   int err, s;
> >>>>>   struct addrinfo *ai;
> >>>>>
> >>>>>   printf("Client\n");
> >>>>>
> >>>>>   err = getaddr("::1", "3023", false, &ai);
> >>>>>   if (err)
> >>>>>       return err;
> >>>>>
> >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> >>>>>   if (s = -1) {
> >>>>>       perror("socket");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> >>>>>   if (err = -1) {
> >>>>>       perror("connect");
> >>>>>       return -1;
> >>>>>   }
> >>>>>
> >>>>>   err = waitread(s);
> >>>>>   close(s);
> >>>>>   return err;
> >>>>> }
> >>>>>
> >>>>> int
> >>>>> main(int argc, char *argv[])
> >>>>> {
> >>>>>   int err;
> >>>>>
> >>>>>   if (argc > 1)
> >>>>>       err = do_server();
> >>>>>   else
> >>>>>       err = do_client();
> >>>>>   return !!err;
> >>>>> }
> >>>>>
> >>
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* RE: Strange problem with SCTP+IPv6
  2020-06-22 18:32         ` Marcelo Ricardo Leitner
  (?)
  (?)
@ 2020-06-23 13:17         ` David Laight
  2020-06-23 16:04             ` minyard
                             ` (2 more replies)
  -1 siblings, 3 replies; 55+ messages in thread
From: David Laight @ 2020-06-23 13:17 UTC (permalink / raw)
  To: 'Marcelo Ricardo Leitner', Michael Tuexen
  Cc: minyard, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp, LKML

From: Marcelo Ricardo Leitner
> Sent: 22 June 2020 19:33
> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > >
> > > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > >>>
> > >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > >>> then I make a connection to it using ::1, the connection will drop after
> > >>> 2.5 seconds with an ECONNRESET error.
> > >>>
> > >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > >>> I tried on an ARM system and x86_64.
> > >>>
> > >>> I haven't dug into the kernel to see if I could find anything yet, but I
> > >>> thought I would go ahead and report it.  I am attaching a reproducer.
> > >>> Basically, compile the following code:
> > >> The code only set IPV6_V6ONLY on server side, so the client side will
> > >> still bind all the local ipv4 addresses (as you didn't call bind() to
> > >> bind any specific addresses ). Then after the connection is created,
> > >> the client will send HB on the v4 paths to the server. The server
> > >> will abort the connection, as it can't support v4.
> > >>
> > >> So you can work around it by either:
> > >>
> > >>  - set IPV6_V6ONLY on client side.
> > >>
> > >> or
> > >>
> > >>  - bind to the specific v6 addresses on the client side.
> > >>
> > >> I don't see RFC said something about this.
> > >> So it may not be a good idea to change the current behaviour
> > >> to not establish the connection in this case, which may cause regression.
> > >
> > > Ok, I understand this.  It's a little strange, but I see why it works
> > > this way.
> > I don't. I would expect it to work as I described in my email.
> > Could someone explain me how and why it is behaving different from
> > my expectation?
> 
> It looks like a bug to me. Testing with this test app here, I can see
> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> that's unexpected for a v6only socket. As is, it's the server saying
> "I'm available at these other addresses too, but not."

Does it even make sense to mix IPv4 and IPv6 addresses on the same
connection?
I don't remember ever seeing both types of address in a message,
but may not have looked.

I also wonder whether the connection should be dropped for an error
response on a path that has never been validated.

OTOH the whole 'multi-homing' part of SCTP sucks.
The IP addresses a server needs to bind to depend on where the
incoming connection will come from.
A local connection may be able to use a 192.168.x.x address
but a remote connection must not - as it may be defined locally
at the remote system.
But both connections can come into the public (routable) address.
We have to tell customers to explicitly configure the local IP
addresses - which means the application has to know what they are.
Fortunately these apps are pretty static - usually M3UA.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 10:13             ` Xin Long
@ 2020-06-23 13:29               ` Corey Minyard
  -1 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 13:29 UTC (permalink / raw)
  To: Xin Long
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> <Michael.Tuexen@lurchi.franken.de> wrote:
> >
> > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > >
> > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > >>>
> > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > >>>>>
> > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > >>>>> then I make a connection to it using ::1, the connection will drop after
> > >>>>> 2.5 seconds with an ECONNRESET error.
> > >>>>>
> > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > >>>>> I tried on an ARM system and x86_64.
> > >>>>>
> > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > >>>>> Basically, compile the following code:
> > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > >>>> bind any specific addresses ). Then after the connection is created,
> > >>>> the client will send HB on the v4 paths to the server. The server
> > >>>> will abort the connection, as it can't support v4.
> > >>>>
> > >>>> So you can work around it by either:
> > >>>>
> > >>>> - set IPV6_V6ONLY on client side.
> > >>>>
> > >>>> or
> > >>>>
> > >>>> - bind to the specific v6 addresses on the client side.
> > >>>>
> > >>>> I don't see RFC said something about this.
> > >>>> So it may not be a good idea to change the current behaviour
> > >>>> to not establish the connection in this case, which may cause regression.
> > >>>
> > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > >>> this way.
> > >> I don't. I would expect it to work as I described in my email.
> > >> Could someone explain me how and why it is behaving different from
> > >> my expectation?
> > >
> > > It looks like a bug to me. Testing with this test app here, I can see
> > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > that's unexpected for a v6only socket. As is, it's the server saying
> > > "I'm available at these other addresses too, but not."
> > I agree.
> Then we need a fix in sctp_bind_addrs_to_raw():
> 
> @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> struct sctp_bind_addr *bp,
>         addrparms = retval;
> 
>         list_for_each_entry(addr, &bp->address_list, list) {
> +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
> +                   (AF_INET == addr->a.sa.sa_family))
> +                       continue;

This does not compile in the latest mainline.  sk is not defined.
Also, if you could send a normal git patch, that would be easier to 
manage.

Thanks,

-corey

>                 af = sctp_get_af_specific(addr->a.v4.sin_family);
>                 len = af->to_addr_param(&addr->a, &rawaddr);
>                 memcpy(addrparms.v, &rawaddr, len);
> 
> >
> > Best regards
> > Michael
> > >
> > > Thanks,
> > > Marcelo
> > >
> > >>
> > >> Best regards
> > >> Michael
> > >>>
> > >>> Thanks,
> > >>>
> > >>> -corey
> > >>>
> > >>>>
> > >>>>>
> > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > >>>>>
> > >>>>> and run it in one window as a server:
> > >>>>>
> > >>>>> ./sctptest a
> > >>>>>
> > >>>>> (Pass in any option to be the server) and run the following in another
> > >>>>> window as the client:
> > >>>>>
> > >>>>> ./sctptest
> > >>>>>
> > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > >>>>> there forever.
> > >>>>>
> > >>>>> -corey
> > >>>>>
> > >>>>>
> > >>>>> #include <stdio.h>
> > >>>>> #include <stdbool.h>
> > >>>>> #include <string.h>
> > >>>>> #include <unistd.h>
> > >>>>> #include <fcntl.h>
> > >>>>> #include <sys/select.h>
> > >>>>> #include <arpa/inet.h>
> > >>>>> #include <netinet/sctp.h>
> > >>>>> #include <sys/types.h>
> > >>>>> #include <sys/socket.h>
> > >>>>> #include <netdb.h>
> > >>>>>
> > >>>>> static int
> > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > >>>>>       struct addrinfo **rai)
> > >>>>> {
> > >>>>>   struct addrinfo *ai, hints;
> > >>>>>
> > >>>>>   memset(&hints, 0, sizeof(hints));
> > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > >>>>>   if (listen)
> > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > >>>>>   hints.ai_family = AF_UNSPEC;
> > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > >>>>>       perror("getaddrinfo");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   *rai = ai;
> > >>>>>   return 0;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> waitread(int s)
> > >>>>> {
> > >>>>>   char data[1];
> > >>>>>   ssize_t rv;
> > >>>>>
> > >>>>>   rv = read(s, data, sizeof(data));
> > >>>>>   if (rv == -1) {
> > >>>>>       perror("read");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>   printf("Read %d bytes\n", (int) rv);
> > >>>>>   return 0;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> do_server(void)
> > >>>>> {
> > >>>>>   int err, ls, s, optval;
> > >>>>>   struct addrinfo *ai;
> > >>>>>
> > >>>>>   printf("Server\n");
> > >>>>>
> > >>>>>   err = getaddr("::", "3023", true, &ai);
> > >>>>>   if (err)
> > >>>>>       return err;
> > >>>>>
> > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > >>>>>   if (ls == -1) {
> > >>>>>       perror("socket");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   optval = 1;
> > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > >>>>>                  (void *)&optval, sizeof(optval)) == -1) {
> > >>>>>       perror("setsockopt reuseaddr");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   /* Comment this out and it will work. */
> > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > >>>>>                  sizeof(optval)) == -1) {
> > >>>>>       perror("setsockopt ipv6 only");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > >>>>>   if (err == -1) {
> > >>>>>       perror("bind");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = listen(ls, 5);
> > >>>>>   if (err == -1) {
> > >>>>>       perror("listen");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   s = accept(ls, NULL, NULL);
> > >>>>>   if (s == -1) {
> > >>>>>       perror("accept");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   close(ls);
> > >>>>>
> > >>>>>   err = waitread(s);
> > >>>>>   close(s);
> > >>>>>   return err;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> do_client(void)
> > >>>>> {
> > >>>>>   int err, s;
> > >>>>>   struct addrinfo *ai;
> > >>>>>
> > >>>>>   printf("Client\n");
> > >>>>>
> > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > >>>>>   if (err)
> > >>>>>       return err;
> > >>>>>
> > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > >>>>>   if (s == -1) {
> > >>>>>       perror("socket");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > >>>>>   if (err == -1) {
> > >>>>>       perror("connect");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = waitread(s);
> > >>>>>   close(s);
> > >>>>>   return err;
> > >>>>> }
> > >>>>>
> > >>>>> int
> > >>>>> main(int argc, char *argv[])
> > >>>>> {
> > >>>>>   int err;
> > >>>>>
> > >>>>>   if (argc > 1)
> > >>>>>       err = do_server();
> > >>>>>   else
> > >>>>>       err = do_client();
> > >>>>>   return !!err;
> > >>>>> }
> > >>>>>
> > >>
> >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 13:29               ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 13:29 UTC (permalink / raw)
  To: Xin Long
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> <Michael.Tuexen@lurchi.franken.de> wrote:
> >
> > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > >
> > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > >>>
> > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > >>>>>
> > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > >>>>> then I make a connection to it using ::1, the connection will drop after
> > >>>>> 2.5 seconds with an ECONNRESET error.
> > >>>>>
> > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > >>>>> I tried on an ARM system and x86_64.
> > >>>>>
> > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > >>>>> Basically, compile the following code:
> > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > >>>> bind any specific addresses ). Then after the connection is created,
> > >>>> the client will send HB on the v4 paths to the server. The server
> > >>>> will abort the connection, as it can't support v4.
> > >>>>
> > >>>> So you can work around it by either:
> > >>>>
> > >>>> - set IPV6_V6ONLY on client side.
> > >>>>
> > >>>> or
> > >>>>
> > >>>> - bind to the specific v6 addresses on the client side.
> > >>>>
> > >>>> I don't see RFC said something about this.
> > >>>> So it may not be a good idea to change the current behaviour
> > >>>> to not establish the connection in this case, which may cause regression.
> > >>>
> > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > >>> this way.
> > >> I don't. I would expect it to work as I described in my email.
> > >> Could someone explain me how and why it is behaving different from
> > >> my expectation?
> > >
> > > It looks like a bug to me. Testing with this test app here, I can see
> > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > that's unexpected for a v6only socket. As is, it's the server saying
> > > "I'm available at these other addresses too, but not."
> > I agree.
> Then we need a fix in sctp_bind_addrs_to_raw():
> 
> @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> struct sctp_bind_addr *bp,
>         addrparms = retval;
> 
>         list_for_each_entry(addr, &bp->address_list, list) {
> +               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
> +                   (AF_INET = addr->a.sa.sa_family))
> +                       continue;

This does not compile in the latest mainline.  sk is not defined.
Also, if you could send a normal git patch, that would be easier to 
manage.

Thanks,

-corey

>                 af = sctp_get_af_specific(addr->a.v4.sin_family);
>                 len = af->to_addr_param(&addr->a, &rawaddr);
>                 memcpy(addrparms.v, &rawaddr, len);
> 
> >
> > Best regards
> > Michael
> > >
> > > Thanks,
> > > Marcelo
> > >
> > >>
> > >> Best regards
> > >> Michael
> > >>>
> > >>> Thanks,
> > >>>
> > >>> -corey
> > >>>
> > >>>>
> > >>>>>
> > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > >>>>>
> > >>>>> and run it in one window as a server:
> > >>>>>
> > >>>>> ./sctptest a
> > >>>>>
> > >>>>> (Pass in any option to be the server) and run the following in another
> > >>>>> window as the client:
> > >>>>>
> > >>>>> ./sctptest
> > >>>>>
> > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > >>>>> there forever.
> > >>>>>
> > >>>>> -corey
> > >>>>>
> > >>>>>
> > >>>>> #include <stdio.h>
> > >>>>> #include <stdbool.h>
> > >>>>> #include <string.h>
> > >>>>> #include <unistd.h>
> > >>>>> #include <fcntl.h>
> > >>>>> #include <sys/select.h>
> > >>>>> #include <arpa/inet.h>
> > >>>>> #include <netinet/sctp.h>
> > >>>>> #include <sys/types.h>
> > >>>>> #include <sys/socket.h>
> > >>>>> #include <netdb.h>
> > >>>>>
> > >>>>> static int
> > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > >>>>>       struct addrinfo **rai)
> > >>>>> {
> > >>>>>   struct addrinfo *ai, hints;
> > >>>>>
> > >>>>>   memset(&hints, 0, sizeof(hints));
> > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > >>>>>   if (listen)
> > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > >>>>>   hints.ai_family = AF_UNSPEC;
> > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > >>>>>       perror("getaddrinfo");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   *rai = ai;
> > >>>>>   return 0;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> waitread(int s)
> > >>>>> {
> > >>>>>   char data[1];
> > >>>>>   ssize_t rv;
> > >>>>>
> > >>>>>   rv = read(s, data, sizeof(data));
> > >>>>>   if (rv = -1) {
> > >>>>>       perror("read");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>   printf("Read %d bytes\n", (int) rv);
> > >>>>>   return 0;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> do_server(void)
> > >>>>> {
> > >>>>>   int err, ls, s, optval;
> > >>>>>   struct addrinfo *ai;
> > >>>>>
> > >>>>>   printf("Server\n");
> > >>>>>
> > >>>>>   err = getaddr("::", "3023", true, &ai);
> > >>>>>   if (err)
> > >>>>>       return err;
> > >>>>>
> > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > >>>>>   if (ls = -1) {
> > >>>>>       perror("socket");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   optval = 1;
> > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > >>>>>                  (void *)&optval, sizeof(optval)) = -1) {
> > >>>>>       perror("setsockopt reuseaddr");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   /* Comment this out and it will work. */
> > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > >>>>>                  sizeof(optval)) = -1) {
> > >>>>>       perror("setsockopt ipv6 only");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > >>>>>   if (err = -1) {
> > >>>>>       perror("bind");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = listen(ls, 5);
> > >>>>>   if (err = -1) {
> > >>>>>       perror("listen");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   s = accept(ls, NULL, NULL);
> > >>>>>   if (s = -1) {
> > >>>>>       perror("accept");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   close(ls);
> > >>>>>
> > >>>>>   err = waitread(s);
> > >>>>>   close(s);
> > >>>>>   return err;
> > >>>>> }
> > >>>>>
> > >>>>> static int
> > >>>>> do_client(void)
> > >>>>> {
> > >>>>>   int err, s;
> > >>>>>   struct addrinfo *ai;
> > >>>>>
> > >>>>>   printf("Client\n");
> > >>>>>
> > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > >>>>>   if (err)
> > >>>>>       return err;
> > >>>>>
> > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > >>>>>   if (s = -1) {
> > >>>>>       perror("socket");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > >>>>>   if (err = -1) {
> > >>>>>       perror("connect");
> > >>>>>       return -1;
> > >>>>>   }
> > >>>>>
> > >>>>>   err = waitread(s);
> > >>>>>   close(s);
> > >>>>>   return err;
> > >>>>> }
> > >>>>>
> > >>>>> int
> > >>>>> main(int argc, char *argv[])
> > >>>>> {
> > >>>>>   int err;
> > >>>>>
> > >>>>>   if (argc > 1)
> > >>>>>       err = do_server();
> > >>>>>   else
> > >>>>>       err = do_client();
> > >>>>>   return !!err;
> > >>>>> }
> > >>>>>
> > >>
> >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 13:29               ` Corey Minyard
@ 2020-06-23 15:40                 ` Xin Long
  -1 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-23 15:40 UTC (permalink / raw)
  To: minyard
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
>
> On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > <Michael.Tuexen@lurchi.franken.de> wrote:
> > >
> > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > >
> > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > >>>
> > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > >>>>>
> > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > >>>>>
> > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > >>>>> I tried on an ARM system and x86_64.
> > > >>>>>
> > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > >>>>> Basically, compile the following code:
> > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > >>>> bind any specific addresses ). Then after the connection is created,
> > > >>>> the client will send HB on the v4 paths to the server. The server
> > > >>>> will abort the connection, as it can't support v4.
> > > >>>>
> > > >>>> So you can work around it by either:
> > > >>>>
> > > >>>> - set IPV6_V6ONLY on client side.
> > > >>>>
> > > >>>> or
> > > >>>>
> > > >>>> - bind to the specific v6 addresses on the client side.
> > > >>>>
> > > >>>> I don't see RFC said something about this.
> > > >>>> So it may not be a good idea to change the current behaviour
> > > >>>> to not establish the connection in this case, which may cause regression.
> > > >>>
> > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > >>> this way.
> > > >> I don't. I would expect it to work as I described in my email.
> > > >> Could someone explain me how and why it is behaving different from
> > > >> my expectation?
> > > >
> > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > "I'm available at these other addresses too, but not."
> > > I agree.
> > Then we need a fix in sctp_bind_addrs_to_raw():
> >
> > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > struct sctp_bind_addr *bp,
> >         addrparms = retval;
> >
> >         list_for_each_entry(addr, &bp->address_list, list) {
> > +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
> > +                   (AF_INET == addr->a.sa.sa_family))
> > +                       continue;
>
> This does not compile in the latest mainline.  sk is not defined.
> Also, if you could send a normal git patch, that would be easier to
> manage.
sorry, that was just the code to show the idea.

For the compilable one, pls see:
https://paste.centos.org/view/49f5ff5a

Thanks.
>
> Thanks,
>
> -corey
>
> >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> >                 len = af->to_addr_param(&addr->a, &rawaddr);
> >                 memcpy(addrparms.v, &rawaddr, len);
> >
> > >
> > > Best regards
> > > Michael
> > > >
> > > > Thanks,
> > > > Marcelo
> > > >
> > > >>
> > > >> Best regards
> > > >> Michael
> > > >>>
> > > >>> Thanks,
> > > >>>
> > > >>> -corey
> > > >>>
> > > >>>>
> > > >>>>>
> > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > >>>>>
> > > >>>>> and run it in one window as a server:
> > > >>>>>
> > > >>>>> ./sctptest a
> > > >>>>>
> > > >>>>> (Pass in any option to be the server) and run the following in another
> > > >>>>> window as the client:
> > > >>>>>
> > > >>>>> ./sctptest
> > > >>>>>
> > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > >>>>> there forever.
> > > >>>>>
> > > >>>>> -corey
> > > >>>>>
> > > >>>>>
> > > >>>>> #include <stdio.h>
> > > >>>>> #include <stdbool.h>
> > > >>>>> #include <string.h>
> > > >>>>> #include <unistd.h>
> > > >>>>> #include <fcntl.h>
> > > >>>>> #include <sys/select.h>
> > > >>>>> #include <arpa/inet.h>
> > > >>>>> #include <netinet/sctp.h>
> > > >>>>> #include <sys/types.h>
> > > >>>>> #include <sys/socket.h>
> > > >>>>> #include <netdb.h>
> > > >>>>>
> > > >>>>> static int
> > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > >>>>>       struct addrinfo **rai)
> > > >>>>> {
> > > >>>>>   struct addrinfo *ai, hints;
> > > >>>>>
> > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > >>>>>   if (listen)
> > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > >>>>>       perror("getaddrinfo");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   *rai = ai;
> > > >>>>>   return 0;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> waitread(int s)
> > > >>>>> {
> > > >>>>>   char data[1];
> > > >>>>>   ssize_t rv;
> > > >>>>>
> > > >>>>>   rv = read(s, data, sizeof(data));
> > > >>>>>   if (rv == -1) {
> > > >>>>>       perror("read");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > >>>>>   return 0;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> do_server(void)
> > > >>>>> {
> > > >>>>>   int err, ls, s, optval;
> > > >>>>>   struct addrinfo *ai;
> > > >>>>>
> > > >>>>>   printf("Server\n");
> > > >>>>>
> > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > >>>>>   if (err)
> > > >>>>>       return err;
> > > >>>>>
> > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > >>>>>   if (ls == -1) {
> > > >>>>>       perror("socket");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   optval = 1;
> > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > >>>>>                  (void *)&optval, sizeof(optval)) == -1) {
> > > >>>>>       perror("setsockopt reuseaddr");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   /* Comment this out and it will work. */
> > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > >>>>>                  sizeof(optval)) == -1) {
> > > >>>>>       perror("setsockopt ipv6 only");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > >>>>>   if (err == -1) {
> > > >>>>>       perror("bind");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = listen(ls, 5);
> > > >>>>>   if (err == -1) {
> > > >>>>>       perror("listen");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   s = accept(ls, NULL, NULL);
> > > >>>>>   if (s == -1) {
> > > >>>>>       perror("accept");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   close(ls);
> > > >>>>>
> > > >>>>>   err = waitread(s);
> > > >>>>>   close(s);
> > > >>>>>   return err;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> do_client(void)
> > > >>>>> {
> > > >>>>>   int err, s;
> > > >>>>>   struct addrinfo *ai;
> > > >>>>>
> > > >>>>>   printf("Client\n");
> > > >>>>>
> > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > >>>>>   if (err)
> > > >>>>>       return err;
> > > >>>>>
> > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > >>>>>   if (s == -1) {
> > > >>>>>       perror("socket");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > >>>>>   if (err == -1) {
> > > >>>>>       perror("connect");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = waitread(s);
> > > >>>>>   close(s);
> > > >>>>>   return err;
> > > >>>>> }
> > > >>>>>
> > > >>>>> int
> > > >>>>> main(int argc, char *argv[])
> > > >>>>> {
> > > >>>>>   int err;
> > > >>>>>
> > > >>>>>   if (argc > 1)
> > > >>>>>       err = do_server();
> > > >>>>>   else
> > > >>>>>       err = do_client();
> > > >>>>>   return !!err;
> > > >>>>> }
> > > >>>>>
> > > >>
> > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 15:40                 ` Xin Long
  0 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-23 15:40 UTC (permalink / raw)
  To: minyard
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
>
> On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > <Michael.Tuexen@lurchi.franken.de> wrote:
> > >
> > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > >
> > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > >>>
> > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > >>>>>
> > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > >>>>>
> > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > >>>>> I tried on an ARM system and x86_64.
> > > >>>>>
> > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > >>>>> Basically, compile the following code:
> > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > >>>> bind any specific addresses ). Then after the connection is created,
> > > >>>> the client will send HB on the v4 paths to the server. The server
> > > >>>> will abort the connection, as it can't support v4.
> > > >>>>
> > > >>>> So you can work around it by either:
> > > >>>>
> > > >>>> - set IPV6_V6ONLY on client side.
> > > >>>>
> > > >>>> or
> > > >>>>
> > > >>>> - bind to the specific v6 addresses on the client side.
> > > >>>>
> > > >>>> I don't see RFC said something about this.
> > > >>>> So it may not be a good idea to change the current behaviour
> > > >>>> to not establish the connection in this case, which may cause regression.
> > > >>>
> > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > >>> this way.
> > > >> I don't. I would expect it to work as I described in my email.
> > > >> Could someone explain me how and why it is behaving different from
> > > >> my expectation?
> > > >
> > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > "I'm available at these other addresses too, but not."
> > > I agree.
> > Then we need a fix in sctp_bind_addrs_to_raw():
> >
> > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > struct sctp_bind_addr *bp,
> >         addrparms = retval;
> >
> >         list_for_each_entry(addr, &bp->address_list, list) {
> > +               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
> > +                   (AF_INET = addr->a.sa.sa_family))
> > +                       continue;
>
> This does not compile in the latest mainline.  sk is not defined.
> Also, if you could send a normal git patch, that would be easier to
> manage.
sorry, that was just the code to show the idea.

For the compilable one, pls see:
https://paste.centos.org/view/49f5ff5a

Thanks.
>
> Thanks,
>
> -corey
>
> >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> >                 len = af->to_addr_param(&addr->a, &rawaddr);
> >                 memcpy(addrparms.v, &rawaddr, len);
> >
> > >
> > > Best regards
> > > Michael
> > > >
> > > > Thanks,
> > > > Marcelo
> > > >
> > > >>
> > > >> Best regards
> > > >> Michael
> > > >>>
> > > >>> Thanks,
> > > >>>
> > > >>> -corey
> > > >>>
> > > >>>>
> > > >>>>>
> > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > >>>>>
> > > >>>>> and run it in one window as a server:
> > > >>>>>
> > > >>>>> ./sctptest a
> > > >>>>>
> > > >>>>> (Pass in any option to be the server) and run the following in another
> > > >>>>> window as the client:
> > > >>>>>
> > > >>>>> ./sctptest
> > > >>>>>
> > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > >>>>> there forever.
> > > >>>>>
> > > >>>>> -corey
> > > >>>>>
> > > >>>>>
> > > >>>>> #include <stdio.h>
> > > >>>>> #include <stdbool.h>
> > > >>>>> #include <string.h>
> > > >>>>> #include <unistd.h>
> > > >>>>> #include <fcntl.h>
> > > >>>>> #include <sys/select.h>
> > > >>>>> #include <arpa/inet.h>
> > > >>>>> #include <netinet/sctp.h>
> > > >>>>> #include <sys/types.h>
> > > >>>>> #include <sys/socket.h>
> > > >>>>> #include <netdb.h>
> > > >>>>>
> > > >>>>> static int
> > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > >>>>>       struct addrinfo **rai)
> > > >>>>> {
> > > >>>>>   struct addrinfo *ai, hints;
> > > >>>>>
> > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > >>>>>   if (listen)
> > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > >>>>>       perror("getaddrinfo");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   *rai = ai;
> > > >>>>>   return 0;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> waitread(int s)
> > > >>>>> {
> > > >>>>>   char data[1];
> > > >>>>>   ssize_t rv;
> > > >>>>>
> > > >>>>>   rv = read(s, data, sizeof(data));
> > > >>>>>   if (rv = -1) {
> > > >>>>>       perror("read");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > >>>>>   return 0;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> do_server(void)
> > > >>>>> {
> > > >>>>>   int err, ls, s, optval;
> > > >>>>>   struct addrinfo *ai;
> > > >>>>>
> > > >>>>>   printf("Server\n");
> > > >>>>>
> > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > >>>>>   if (err)
> > > >>>>>       return err;
> > > >>>>>
> > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > >>>>>   if (ls = -1) {
> > > >>>>>       perror("socket");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   optval = 1;
> > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > >>>>>                  (void *)&optval, sizeof(optval)) = -1) {
> > > >>>>>       perror("setsockopt reuseaddr");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   /* Comment this out and it will work. */
> > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > >>>>>                  sizeof(optval)) = -1) {
> > > >>>>>       perror("setsockopt ipv6 only");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > >>>>>   if (err = -1) {
> > > >>>>>       perror("bind");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = listen(ls, 5);
> > > >>>>>   if (err = -1) {
> > > >>>>>       perror("listen");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   s = accept(ls, NULL, NULL);
> > > >>>>>   if (s = -1) {
> > > >>>>>       perror("accept");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   close(ls);
> > > >>>>>
> > > >>>>>   err = waitread(s);
> > > >>>>>   close(s);
> > > >>>>>   return err;
> > > >>>>> }
> > > >>>>>
> > > >>>>> static int
> > > >>>>> do_client(void)
> > > >>>>> {
> > > >>>>>   int err, s;
> > > >>>>>   struct addrinfo *ai;
> > > >>>>>
> > > >>>>>   printf("Client\n");
> > > >>>>>
> > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > >>>>>   if (err)
> > > >>>>>       return err;
> > > >>>>>
> > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > >>>>>   if (s = -1) {
> > > >>>>>       perror("socket");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > >>>>>   if (err = -1) {
> > > >>>>>       perror("connect");
> > > >>>>>       return -1;
> > > >>>>>   }
> > > >>>>>
> > > >>>>>   err = waitread(s);
> > > >>>>>   close(s);
> > > >>>>>   return err;
> > > >>>>> }
> > > >>>>>
> > > >>>>> int
> > > >>>>> main(int argc, char *argv[])
> > > >>>>> {
> > > >>>>>   int err;
> > > >>>>>
> > > >>>>>   if (argc > 1)
> > > >>>>>       err = do_server();
> > > >>>>>   else
> > > >>>>>       err = do_client();
> > > >>>>>   return !!err;
> > > >>>>> }
> > > >>>>>
> > > >>
> > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 15:40                 ` Xin Long
@ 2020-06-23 16:00                   ` Corey Minyard
  -1 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 16:00 UTC (permalink / raw)
  To: Xin Long
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:40:21PM +0800, Xin Long wrote:
> On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
> >
> > On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > > <Michael.Tuexen@lurchi.franken.de> wrote:
> > > >
> > > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > > >
> > > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > >>>
> > > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > >>>>>
> > > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > > >>>>>
> > > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > >>>>> I tried on an ARM system and x86_64.
> > > > >>>>>
> > > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > >>>>> Basically, compile the following code:
> > > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > >>>> bind any specific addresses ). Then after the connection is created,
> > > > >>>> the client will send HB on the v4 paths to the server. The server
> > > > >>>> will abort the connection, as it can't support v4.
> > > > >>>>
> > > > >>>> So you can work around it by either:
> > > > >>>>
> > > > >>>> - set IPV6_V6ONLY on client side.
> > > > >>>>
> > > > >>>> or
> > > > >>>>
> > > > >>>> - bind to the specific v6 addresses on the client side.
> > > > >>>>
> > > > >>>> I don't see RFC said something about this.
> > > > >>>> So it may not be a good idea to change the current behaviour
> > > > >>>> to not establish the connection in this case, which may cause regression.
> > > > >>>
> > > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > > >>> this way.
> > > > >> I don't. I would expect it to work as I described in my email.
> > > > >> Could someone explain me how and why it is behaving different from
> > > > >> my expectation?
> > > > >
> > > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > > "I'm available at these other addresses too, but not."
> > > > I agree.
> > > Then we need a fix in sctp_bind_addrs_to_raw():
> > >
> > > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > > struct sctp_bind_addr *bp,
> > >         addrparms = retval;
> > >
> > >         list_for_each_entry(addr, &bp->address_list, list) {
> > > +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
> > > +                   (AF_INET == addr->a.sa.sa_family))
> > > +                       continue;
> >
> > This does not compile in the latest mainline.  sk is not defined.
> > Also, if you could send a normal git patch, that would be easier to
> > manage.
> sorry, that was just the code to show the idea.
> 
> For the compilable one, pls see:
> https://paste.centos.org/view/49f5ff5a

The kernel community runs on patches.  It's hard to talk about changes
if you put things in pastbin type of stuff.  Please send full complete
patches in emails.  I will do that in a moment.

Anyway, are use sure every bp passed into sctp_bind_addrs_to_raw()
is &asoc->base.bind_addr?  It's passed in to sctp_make_init() and the
passed to sctp_bind_addrs_to_raw().  If this is the case, you can remove
it from the parameters of sctp_make_init().  But I suspect it's passed
in for a reason.

Anyway, I have a patch I have compiled and tested, I will send that.

-corey

> 
> Thanks.
> >
> > Thanks,
> >
> > -corey
> >
> > >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> > >                 len = af->to_addr_param(&addr->a, &rawaddr);
> > >                 memcpy(addrparms.v, &rawaddr, len);
> > >
> > > >
> > > > Best regards
> > > > Michael
> > > > >
> > > > > Thanks,
> > > > > Marcelo
> > > > >
> > > > >>
> > > > >> Best regards
> > > > >> Michael
> > > > >>>
> > > > >>> Thanks,
> > > > >>>
> > > > >>> -corey
> > > > >>>
> > > > >>>>
> > > > >>>>>
> > > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > > >>>>>
> > > > >>>>> and run it in one window as a server:
> > > > >>>>>
> > > > >>>>> ./sctptest a
> > > > >>>>>
> > > > >>>>> (Pass in any option to be the server) and run the following in another
> > > > >>>>> window as the client:
> > > > >>>>>
> > > > >>>>> ./sctptest
> > > > >>>>>
> > > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > > >>>>> there forever.
> > > > >>>>>
> > > > >>>>> -corey
> > > > >>>>>
> > > > >>>>>
> > > > >>>>> #include <stdio.h>
> > > > >>>>> #include <stdbool.h>
> > > > >>>>> #include <string.h>
> > > > >>>>> #include <unistd.h>
> > > > >>>>> #include <fcntl.h>
> > > > >>>>> #include <sys/select.h>
> > > > >>>>> #include <arpa/inet.h>
> > > > >>>>> #include <netinet/sctp.h>
> > > > >>>>> #include <sys/types.h>
> > > > >>>>> #include <sys/socket.h>
> > > > >>>>> #include <netdb.h>
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > > >>>>>       struct addrinfo **rai)
> > > > >>>>> {
> > > > >>>>>   struct addrinfo *ai, hints;
> > > > >>>>>
> > > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > > >>>>>   if (listen)
> > > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > > >>>>>       perror("getaddrinfo");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   *rai = ai;
> > > > >>>>>   return 0;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> waitread(int s)
> > > > >>>>> {
> > > > >>>>>   char data[1];
> > > > >>>>>   ssize_t rv;
> > > > >>>>>
> > > > >>>>>   rv = read(s, data, sizeof(data));
> > > > >>>>>   if (rv == -1) {
> > > > >>>>>       perror("read");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > > >>>>>   return 0;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> do_server(void)
> > > > >>>>> {
> > > > >>>>>   int err, ls, s, optval;
> > > > >>>>>   struct addrinfo *ai;
> > > > >>>>>
> > > > >>>>>   printf("Server\n");
> > > > >>>>>
> > > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > > >>>>>   if (err)
> > > > >>>>>       return err;
> > > > >>>>>
> > > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > >>>>>   if (ls == -1) {
> > > > >>>>>       perror("socket");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   optval = 1;
> > > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > > >>>>>                  (void *)&optval, sizeof(optval)) == -1) {
> > > > >>>>>       perror("setsockopt reuseaddr");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   /* Comment this out and it will work. */
> > > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > > >>>>>                  sizeof(optval)) == -1) {
> > > > >>>>>       perror("setsockopt ipv6 only");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > > >>>>>   if (err == -1) {
> > > > >>>>>       perror("bind");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = listen(ls, 5);
> > > > >>>>>   if (err == -1) {
> > > > >>>>>       perror("listen");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   s = accept(ls, NULL, NULL);
> > > > >>>>>   if (s == -1) {
> > > > >>>>>       perror("accept");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   close(ls);
> > > > >>>>>
> > > > >>>>>   err = waitread(s);
> > > > >>>>>   close(s);
> > > > >>>>>   return err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> do_client(void)
> > > > >>>>> {
> > > > >>>>>   int err, s;
> > > > >>>>>   struct addrinfo *ai;
> > > > >>>>>
> > > > >>>>>   printf("Client\n");
> > > > >>>>>
> > > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > > >>>>>   if (err)
> > > > >>>>>       return err;
> > > > >>>>>
> > > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > >>>>>   if (s == -1) {
> > > > >>>>>       perror("socket");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > > >>>>>   if (err == -1) {
> > > > >>>>>       perror("connect");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = waitread(s);
> > > > >>>>>   close(s);
> > > > >>>>>   return err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> int
> > > > >>>>> main(int argc, char *argv[])
> > > > >>>>> {
> > > > >>>>>   int err;
> > > > >>>>>
> > > > >>>>>   if (argc > 1)
> > > > >>>>>       err = do_server();
> > > > >>>>>   else
> > > > >>>>>       err = do_client();
> > > > >>>>>   return !!err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>
> > > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 16:00                   ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 16:00 UTC (permalink / raw)
  To: Xin Long
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:40:21PM +0800, Xin Long wrote:
> On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
> >
> > On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > > <Michael.Tuexen@lurchi.franken.de> wrote:
> > > >
> > > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > > >
> > > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > >>>
> > > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > >>>>>
> > > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > > >>>>>
> > > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > >>>>> I tried on an ARM system and x86_64.
> > > > >>>>>
> > > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > >>>>> Basically, compile the following code:
> > > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > >>>> bind any specific addresses ). Then after the connection is created,
> > > > >>>> the client will send HB on the v4 paths to the server. The server
> > > > >>>> will abort the connection, as it can't support v4.
> > > > >>>>
> > > > >>>> So you can work around it by either:
> > > > >>>>
> > > > >>>> - set IPV6_V6ONLY on client side.
> > > > >>>>
> > > > >>>> or
> > > > >>>>
> > > > >>>> - bind to the specific v6 addresses on the client side.
> > > > >>>>
> > > > >>>> I don't see RFC said something about this.
> > > > >>>> So it may not be a good idea to change the current behaviour
> > > > >>>> to not establish the connection in this case, which may cause regression.
> > > > >>>
> > > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > > >>> this way.
> > > > >> I don't. I would expect it to work as I described in my email.
> > > > >> Could someone explain me how and why it is behaving different from
> > > > >> my expectation?
> > > > >
> > > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > > "I'm available at these other addresses too, but not."
> > > > I agree.
> > > Then we need a fix in sctp_bind_addrs_to_raw():
> > >
> > > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > > struct sctp_bind_addr *bp,
> > >         addrparms = retval;
> > >
> > >         list_for_each_entry(addr, &bp->address_list, list) {
> > > +               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
> > > +                   (AF_INET = addr->a.sa.sa_family))
> > > +                       continue;
> >
> > This does not compile in the latest mainline.  sk is not defined.
> > Also, if you could send a normal git patch, that would be easier to
> > manage.
> sorry, that was just the code to show the idea.
> 
> For the compilable one, pls see:
> https://paste.centos.org/view/49f5ff5a

The kernel community runs on patches.  It's hard to talk about changes
if you put things in pastbin type of stuff.  Please send full complete
patches in emails.  I will do that in a moment.

Anyway, are use sure every bp passed into sctp_bind_addrs_to_raw()
is &asoc->base.bind_addr?  It's passed in to sctp_make_init() and the
passed to sctp_bind_addrs_to_raw().  If this is the case, you can remove
it from the parameters of sctp_make_init().  But I suspect it's passed
in for a reason.

Anyway, I have a patch I have compiled and tested, I will send that.

-corey

> 
> Thanks.
> >
> > Thanks,
> >
> > -corey
> >
> > >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> > >                 len = af->to_addr_param(&addr->a, &rawaddr);
> > >                 memcpy(addrparms.v, &rawaddr, len);
> > >
> > > >
> > > > Best regards
> > > > Michael
> > > > >
> > > > > Thanks,
> > > > > Marcelo
> > > > >
> > > > >>
> > > > >> Best regards
> > > > >> Michael
> > > > >>>
> > > > >>> Thanks,
> > > > >>>
> > > > >>> -corey
> > > > >>>
> > > > >>>>
> > > > >>>>>
> > > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > > >>>>>
> > > > >>>>> and run it in one window as a server:
> > > > >>>>>
> > > > >>>>> ./sctptest a
> > > > >>>>>
> > > > >>>>> (Pass in any option to be the server) and run the following in another
> > > > >>>>> window as the client:
> > > > >>>>>
> > > > >>>>> ./sctptest
> > > > >>>>>
> > > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > > >>>>> there forever.
> > > > >>>>>
> > > > >>>>> -corey
> > > > >>>>>
> > > > >>>>>
> > > > >>>>> #include <stdio.h>
> > > > >>>>> #include <stdbool.h>
> > > > >>>>> #include <string.h>
> > > > >>>>> #include <unistd.h>
> > > > >>>>> #include <fcntl.h>
> > > > >>>>> #include <sys/select.h>
> > > > >>>>> #include <arpa/inet.h>
> > > > >>>>> #include <netinet/sctp.h>
> > > > >>>>> #include <sys/types.h>
> > > > >>>>> #include <sys/socket.h>
> > > > >>>>> #include <netdb.h>
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > > >>>>>       struct addrinfo **rai)
> > > > >>>>> {
> > > > >>>>>   struct addrinfo *ai, hints;
> > > > >>>>>
> > > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > > >>>>>   if (listen)
> > > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > > >>>>>       perror("getaddrinfo");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   *rai = ai;
> > > > >>>>>   return 0;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> waitread(int s)
> > > > >>>>> {
> > > > >>>>>   char data[1];
> > > > >>>>>   ssize_t rv;
> > > > >>>>>
> > > > >>>>>   rv = read(s, data, sizeof(data));
> > > > >>>>>   if (rv = -1) {
> > > > >>>>>       perror("read");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > > >>>>>   return 0;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> do_server(void)
> > > > >>>>> {
> > > > >>>>>   int err, ls, s, optval;
> > > > >>>>>   struct addrinfo *ai;
> > > > >>>>>
> > > > >>>>>   printf("Server\n");
> > > > >>>>>
> > > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > > >>>>>   if (err)
> > > > >>>>>       return err;
> > > > >>>>>
> > > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > >>>>>   if (ls = -1) {
> > > > >>>>>       perror("socket");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   optval = 1;
> > > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > > >>>>>                  (void *)&optval, sizeof(optval)) = -1) {
> > > > >>>>>       perror("setsockopt reuseaddr");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   /* Comment this out and it will work. */
> > > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > > >>>>>                  sizeof(optval)) = -1) {
> > > > >>>>>       perror("setsockopt ipv6 only");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > > >>>>>   if (err = -1) {
> > > > >>>>>       perror("bind");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = listen(ls, 5);
> > > > >>>>>   if (err = -1) {
> > > > >>>>>       perror("listen");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   s = accept(ls, NULL, NULL);
> > > > >>>>>   if (s = -1) {
> > > > >>>>>       perror("accept");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   close(ls);
> > > > >>>>>
> > > > >>>>>   err = waitread(s);
> > > > >>>>>   close(s);
> > > > >>>>>   return err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> static int
> > > > >>>>> do_client(void)
> > > > >>>>> {
> > > > >>>>>   int err, s;
> > > > >>>>>   struct addrinfo *ai;
> > > > >>>>>
> > > > >>>>>   printf("Client\n");
> > > > >>>>>
> > > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > > >>>>>   if (err)
> > > > >>>>>       return err;
> > > > >>>>>
> > > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > >>>>>   if (s = -1) {
> > > > >>>>>       perror("socket");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > > >>>>>   if (err = -1) {
> > > > >>>>>       perror("connect");
> > > > >>>>>       return -1;
> > > > >>>>>   }
> > > > >>>>>
> > > > >>>>>   err = waitread(s);
> > > > >>>>>   close(s);
> > > > >>>>>   return err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>>>> int
> > > > >>>>> main(int argc, char *argv[])
> > > > >>>>> {
> > > > >>>>>   int err;
> > > > >>>>>
> > > > >>>>>   if (argc > 1)
> > > > >>>>>       err = do_server();
> > > > >>>>>   else
> > > > >>>>>       err = do_client();
> > > > >>>>>   return !!err;
> > > > >>>>> }
> > > > >>>>>
> > > > >>
> > > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
  2020-06-23 13:17         ` David Laight
@ 2020-06-23 16:04             ` minyard
  2020-06-23 16:17             ` Corey Minyard
  2020-06-23 17:09             ` Michael Tuexen
  2 siblings, 0 replies; 55+ messages in thread
From: minyard @ 2020-06-23 16:04 UTC (permalink / raw)
  To: Xin Long, Michael Tuexen
  Cc: Marcelo Ricardo Leitner, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

If a socket was set ipv6only, it would still send IPv4 addresses in the
init and init ack packets.  So don't add IPv4 addresses to ipv6only
sockets.

Based on a patch by Xin Long <lucien.xin@gmail.com>

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
I have tested this and it seem to fix the issue.  However, I'm wondering
if it might be better to fix it where the addresses are put into the
association as opposed to where they are put into the message.

 include/net/sctp/structs.h | 3 ++-
 net/sctp/bind_addr.c       | 7 ++++++-
 net/sctp/sm_make_chunk.c   | 5 +++--
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index fb42c90348d3..1e839bf4eaa7 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1190,7 +1190,8 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr	*bp,
 					const union sctp_addr	*addrs,
 					int			addrcnt,
 					struct sctp_sock	*opt);
-union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_association *asoc,
+					 const struct sctp_bind_addr *bp,
 					 int *addrs_len,
 					 gfp_t gfp);
 int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 53bc61537f44..3f5b448f2127 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -202,7 +202,8 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
  *
  * The second argument is the return value for the length.
  */
-union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_association *asoc,
+					 const struct sctp_bind_addr *bp,
 					 int *addrs_len,
 					 gfp_t gfp)
 {
@@ -214,6 +215,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 	struct sctp_sockaddr_entry *addr;
 	struct list_head *pos;
 	struct sctp_af *af;
+	struct sock *sk = asoc->base.sk;
 
 	addrparms_len = 0;
 	len = 0;
@@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 	addrparms = retval;
 
 	list_for_each_entry(addr, &bp->address_list, list) {
+		if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
+		    (AF_INET == addr->a.sa.sa_family))
+			continue;
 		af = sctp_get_af_specific(addr->a.v4.sin_family);
 		len = af->to_addr_param(&addr->a, &rawaddr);
 		memcpy(addrparms.v, &rawaddr, len);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 47910470e532..6e1a6af40779 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -230,7 +230,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
 	 */
 
 	/* Convert the provided bind address list to raw format. */
-	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
+	addrs = sctp_bind_addrs_to_raw(asoc, bp, &addrs_len, gfp);
 
 	init.init_tag		   = htonl(asoc->c.my_vtag);
 	init.a_rwnd		   = htonl(asoc->rwnd);
@@ -397,7 +397,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
 	int addrs_len;
 
 	/* Note: there may be no addresses to embed. */
-	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
+	addrs = sctp_bind_addrs_to_raw(asoc, &asoc->base.bind_addr,
+				       &addrs_len, gfp);
 
 	initack.init_tag	        = htonl(asoc->c.my_vtag);
 	initack.a_rwnd			= htonl(asoc->rwnd);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
@ 2020-06-23 16:04             ` minyard
  0 siblings, 0 replies; 55+ messages in thread
From: minyard @ 2020-06-23 16:04 UTC (permalink / raw)
  To: Xin Long, Michael Tuexen
  Cc: Marcelo Ricardo Leitner, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

If a socket was set ipv6only, it would still send IPv4 addresses in the
init and init ack packets.  So don't add IPv4 addresses to ipv6only
sockets.

Based on a patch by Xin Long <lucien.xin@gmail.com>

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
I have tested this and it seem to fix the issue.  However, I'm wondering
if it might be better to fix it where the addresses are put into the
association as opposed to where they are put into the message.

 include/net/sctp/structs.h | 3 ++-
 net/sctp/bind_addr.c       | 7 ++++++-
 net/sctp/sm_make_chunk.c   | 5 +++--
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index fb42c90348d3..1e839bf4eaa7 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1190,7 +1190,8 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr	*bp,
 					const union sctp_addr	*addrs,
 					int			addrcnt,
 					struct sctp_sock	*opt);
-union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_association *asoc,
+					 const struct sctp_bind_addr *bp,
 					 int *addrs_len,
 					 gfp_t gfp);
 int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 53bc61537f44..3f5b448f2127 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -202,7 +202,8 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
  *
  * The second argument is the return value for the length.
  */
-union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_association *asoc,
+					 const struct sctp_bind_addr *bp,
 					 int *addrs_len,
 					 gfp_t gfp)
 {
@@ -214,6 +215,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 	struct sctp_sockaddr_entry *addr;
 	struct list_head *pos;
 	struct sctp_af *af;
+	struct sock *sk = asoc->base.sk;
 
 	addrparms_len = 0;
 	len = 0;
@@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 	addrparms = retval;
 
 	list_for_each_entry(addr, &bp->address_list, list) {
+		if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
+		    (AF_INET = addr->a.sa.sa_family))
+			continue;
 		af = sctp_get_af_specific(addr->a.v4.sin_family);
 		len = af->to_addr_param(&addr->a, &rawaddr);
 		memcpy(addrparms.v, &rawaddr, len);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 47910470e532..6e1a6af40779 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -230,7 +230,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
 	 */
 
 	/* Convert the provided bind address list to raw format. */
-	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
+	addrs = sctp_bind_addrs_to_raw(asoc, bp, &addrs_len, gfp);
 
 	init.init_tag		   = htonl(asoc->c.my_vtag);
 	init.a_rwnd		   = htonl(asoc->rwnd);
@@ -397,7 +397,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
 	int addrs_len;
 
 	/* Note: there may be no addresses to embed. */
-	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
+	addrs = sctp_bind_addrs_to_raw(asoc, &asoc->base.bind_addr,
+				       &addrs_len, gfp);
 
 	initack.init_tag	        = htonl(asoc->c.my_vtag);
 	initack.a_rwnd			= htonl(asoc->rwnd);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 13:17         ` David Laight
@ 2020-06-23 16:17             ` Corey Minyard
  2020-06-23 16:17             ` Corey Minyard
  2020-06-23 17:09             ` Michael Tuexen
  2 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 16:17 UTC (permalink / raw)
  To: David Laight
  Cc: 'Marcelo Ricardo Leitner',
	Michael Tuexen, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp,
	LKML

On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> From: Marcelo Ricardo Leitner
> > Sent: 22 June 2020 19:33
> > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > >
> > > > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > >>>
> > > >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > >>> then I make a connection to it using ::1, the connection will drop after
> > > >>> 2.5 seconds with an ECONNRESET error.
> > > >>>
> > > >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > >>> I tried on an ARM system and x86_64.
> > > >>>
> > > >>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > >>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > >>> Basically, compile the following code:
> > > >> The code only set IPV6_V6ONLY on server side, so the client side will
> > > >> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > >> bind any specific addresses ). Then after the connection is created,
> > > >> the client will send HB on the v4 paths to the server. The server
> > > >> will abort the connection, as it can't support v4.
> > > >>
> > > >> So you can work around it by either:
> > > >>
> > > >>  - set IPV6_V6ONLY on client side.
> > > >>
> > > >> or
> > > >>
> > > >>  - bind to the specific v6 addresses on the client side.
> > > >>
> > > >> I don't see RFC said something about this.
> > > >> So it may not be a good idea to change the current behaviour
> > > >> to not establish the connection in this case, which may cause regression.
> > > >
> > > > Ok, I understand this.  It's a little strange, but I see why it works
> > > > this way.
> > > I don't. I would expect it to work as I described in my email.
> > > Could someone explain me how and why it is behaving different from
> > > my expectation?
> > 
> > It looks like a bug to me. Testing with this test app here, I can see
> > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > that's unexpected for a v6only socket. As is, it's the server saying
> > "I'm available at these other addresses too, but not."
> 
> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> connection?
> I don't remember ever seeing both types of address in a message,
> but may not have looked.

That's an interesting question.  Do the RFCs say anything?  I would
assume it was ok unless ipv6only was set.

> 
> I also wonder whether the connection should be dropped for an error
> response on a path that has never been validated.

That actually bothered me a bit more.  Shouldn't it stay up if any path
is up?  That's kind of the whole point of multihoming.

> 
> OTOH the whole 'multi-homing' part of SCTP sucks.

I don't think so.

> The IP addresses a server needs to bind to depend on where the
> incoming connection will come from.
> A local connection may be able to use a 192.168.x.x address
> but a remote connection must not - as it may be defined locally
> at the remote system.
> But both connections can come into the public (routable) address.
> We have to tell customers to explicitly configure the local IP
> addresses - which means the application has to know what they are.
> Fortunately these apps are pretty static - usually M3UA.

Umm, no,  If you have a private address, it better be behind a firewall,
and the firewall should handle rewriting the packet to fix the addresses.

It doesn't appear that Linux netfilter does this.  There is a TODO in
the code for this.  But that's how it *should* work.

-corey

> 
> 	David
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 16:17             ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-23 16:17 UTC (permalink / raw)
  To: David Laight
  Cc: 'Marcelo Ricardo Leitner',
	Michael Tuexen, Xin Long, Vlad Yasevich, Neil Horman, linux-sctp,
	LKML

On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> From: Marcelo Ricardo Leitner
> > Sent: 22 June 2020 19:33
> > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > >
> > > > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > >>>
> > > >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > >>> then I make a connection to it using ::1, the connection will drop after
> > > >>> 2.5 seconds with an ECONNRESET error.
> > > >>>
> > > >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > >>> I tried on an ARM system and x86_64.
> > > >>>
> > > >>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > >>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > >>> Basically, compile the following code:
> > > >> The code only set IPV6_V6ONLY on server side, so the client side will
> > > >> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > >> bind any specific addresses ). Then after the connection is created,
> > > >> the client will send HB on the v4 paths to the server. The server
> > > >> will abort the connection, as it can't support v4.
> > > >>
> > > >> So you can work around it by either:
> > > >>
> > > >>  - set IPV6_V6ONLY on client side.
> > > >>
> > > >> or
> > > >>
> > > >>  - bind to the specific v6 addresses on the client side.
> > > >>
> > > >> I don't see RFC said something about this.
> > > >> So it may not be a good idea to change the current behaviour
> > > >> to not establish the connection in this case, which may cause regression.
> > > >
> > > > Ok, I understand this.  It's a little strange, but I see why it works
> > > > this way.
> > > I don't. I would expect it to work as I described in my email.
> > > Could someone explain me how and why it is behaving different from
> > > my expectation?
> > 
> > It looks like a bug to me. Testing with this test app here, I can see
> > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > that's unexpected for a v6only socket. As is, it's the server saying
> > "I'm available at these other addresses too, but not."
> 
> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> connection?
> I don't remember ever seeing both types of address in a message,
> but may not have looked.

That's an interesting question.  Do the RFCs say anything?  I would
assume it was ok unless ipv6only was set.

> 
> I also wonder whether the connection should be dropped for an error
> response on a path that has never been validated.

That actually bothered me a bit more.  Shouldn't it stay up if any path
is up?  That's kind of the whole point of multihoming.

> 
> OTOH the whole 'multi-homing' part of SCTP sucks.

I don't think so.

> The IP addresses a server needs to bind to depend on where the
> incoming connection will come from.
> A local connection may be able to use a 192.168.x.x address
> but a remote connection must not - as it may be defined locally
> at the remote system.
> But both connections can come into the public (routable) address.
> We have to tell customers to explicitly configure the local IP
> addresses - which means the application has to know what they are.
> Fortunately these apps are pretty static - usually M3UA.

Umm, no,  If you have a private address, it better be behind a firewall,
and the firewall should handle rewriting the packet to fix the addresses.

It doesn't appear that Linux netfilter does this.  There is a TODO in
the code for this.  But that's how it *should* work.

-corey

> 
> 	David
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 13:17         ` David Laight
@ 2020-06-23 17:09             ` Michael Tuexen
  2020-06-23 16:17             ` Corey Minyard
  2020-06-23 17:09             ` Michael Tuexen
  2 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 17:09 UTC (permalink / raw)
  To: David Laight
  Cc: Marcelo Ricardo Leitner, minyard, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 15:17, David Laight <David.Laight@ACULAB.COM> wrote:
> 
> From: Marcelo Ricardo Leitner
>> Sent: 22 June 2020 19:33
>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>> 
>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>> 
>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>> 
>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>> I tried on an ARM system and x86_64.
>>>>>> 
>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>> Basically, compile the following code:
>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>> bind any specific addresses ). Then after the connection is created,
>>>>> the client will send HB on the v4 paths to the server. The server
>>>>> will abort the connection, as it can't support v4.
>>>>> 
>>>>> So you can work around it by either:
>>>>> 
>>>>> - set IPV6_V6ONLY on client side.
>>>>> 
>>>>> or
>>>>> 
>>>>> - bind to the specific v6 addresses on the client side.
>>>>> 
>>>>> I don't see RFC said something about this.
>>>>> So it may not be a good idea to change the current behaviour
>>>>> to not establish the connection in this case, which may cause regression.
>>>> 
>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>> this way.
>>> I don't. I would expect it to work as I described in my email.
>>> Could someone explain me how and why it is behaving different from
>>> my expectation?
>> 
>> It looks like a bug to me. Testing with this test app here, I can see
>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>> that's unexpected for a v6only socket. As is, it's the server saying
>> "I'm available at these other addresses too, but not."
> 
> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> connection?
Sure, if you have an IPv6 socket, which has not enabled the IPV6ONLY
socket option.
> I don't remember ever seeing both types of address in a message,
> but may not have looked.
> 
> I also wonder whether the connection should be dropped for an error
> response on a path that has never been validated.
Assuming that it is not an ERROR chunk which comes back, but an ABORT,
this should happen as long as the verification tag is OK.
> 
> OTOH the whole 'multi-homing' part of SCTP sucks.
> The IP addresses a server needs to bind to depend on where the
> incoming connection will come from.
Not sure what this means. The application can bind a wildcard
address or a specific subset. However, when an INIT comes in,
the INIT-ACK might contain only a subset of there due to
scoping.
> A local connection may be able to use a 192.168.x.x address
> but a remote connection must not - as it may be defined locally
> at the remote system.
Yepp. Not sure what you can do about it.
> But both connections can come into the public (routable) address.
> We have to tell customers to explicitly configure the local IP
> addresses - which means the application has to know what they are.
> Fortunately these apps are pretty static - usually M3UA.
Please note that in SIGRTRAN scenarios you normally not have NATs
involved as you have usually in setups used at home.

Best regards
Michael
> 
> 	David
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 17:09             ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 17:09 UTC (permalink / raw)
  To: David Laight
  Cc: Marcelo Ricardo Leitner, minyard, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 15:17, David Laight <David.Laight@ACULAB.COM> wrote:
> 
> From: Marcelo Ricardo Leitner
>> Sent: 22 June 2020 19:33
>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>> 
>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>> 
>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>> 
>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>> I tried on an ARM system and x86_64.
>>>>>> 
>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>> Basically, compile the following code:
>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>> bind any specific addresses ). Then after the connection is created,
>>>>> the client will send HB on the v4 paths to the server. The server
>>>>> will abort the connection, as it can't support v4.
>>>>> 
>>>>> So you can work around it by either:
>>>>> 
>>>>> - set IPV6_V6ONLY on client side.
>>>>> 
>>>>> or
>>>>> 
>>>>> - bind to the specific v6 addresses on the client side.
>>>>> 
>>>>> I don't see RFC said something about this.
>>>>> So it may not be a good idea to change the current behaviour
>>>>> to not establish the connection in this case, which may cause regression.
>>>> 
>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>> this way.
>>> I don't. I would expect it to work as I described in my email.
>>> Could someone explain me how and why it is behaving different from
>>> my expectation?
>> 
>> It looks like a bug to me. Testing with this test app here, I can see
>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>> that's unexpected for a v6only socket. As is, it's the server saying
>> "I'm available at these other addresses too, but not."
> 
> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> connection?
Sure, if you have an IPv6 socket, which has not enabled the IPV6ONLY
socket option.
> I don't remember ever seeing both types of address in a message,
> but may not have looked.
> 
> I also wonder whether the connection should be dropped for an error
> response on a path that has never been validated.
Assuming that it is not an ERROR chunk which comes back, but an ABORT,
this should happen as long as the verification tag is OK.
> 
> OTOH the whole 'multi-homing' part of SCTP sucks.
> The IP addresses a server needs to bind to depend on where the
> incoming connection will come from.
Not sure what this means. The application can bind a wildcard
address or a specific subset. However, when an INIT comes in,
the INIT-ACK might contain only a subset of there due to
scoping.
> A local connection may be able to use a 192.168.x.x address
> but a remote connection must not - as it may be defined locally
> at the remote system.
Yepp. Not sure what you can do about it.
> But both connections can come into the public (routable) address.
> We have to tell customers to explicitly configure the local IP
> addresses - which means the application has to know what they are.
> Fortunately these apps are pretty static - usually M3UA.
Please note that in SIGRTRAN scenarios you normally not have NATs
involved as you have usually in setups used at home.

Best regards
Michael
> 
> 	David
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 16:17             ` Corey Minyard
@ 2020-06-23 21:21               ` 'Marcelo Ricardo Leitner'
  -1 siblings, 0 replies; 55+ messages in thread
From: 'Marcelo Ricardo Leitner' @ 2020-06-23 21:21 UTC (permalink / raw)
  To: Corey Minyard
  Cc: David Laight, Michael Tuexen, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> > From: Marcelo Ricardo Leitner
> > > Sent: 22 June 2020 19:33
> > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > >
> > > > > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > >>>
> > > > >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > >>> then I make a connection to it using ::1, the connection will drop after
> > > > >>> 2.5 seconds with an ECONNRESET error.
> > > > >>>
> > > > >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > >>> I tried on an ARM system and x86_64.
> > > > >>>
> > > > >>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > >>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > >>> Basically, compile the following code:
> > > > >> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > >> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > >> bind any specific addresses ). Then after the connection is created,
> > > > >> the client will send HB on the v4 paths to the server. The server
> > > > >> will abort the connection, as it can't support v4.
> > > > >>
> > > > >> So you can work around it by either:
> > > > >>
> > > > >>  - set IPV6_V6ONLY on client side.
> > > > >>
> > > > >> or
> > > > >>
> > > > >>  - bind to the specific v6 addresses on the client side.
> > > > >>
> > > > >> I don't see RFC said something about this.
> > > > >> So it may not be a good idea to change the current behaviour
> > > > >> to not establish the connection in this case, which may cause regression.
> > > > >
> > > > > Ok, I understand this.  It's a little strange, but I see why it works
> > > > > this way.
> > > > I don't. I would expect it to work as I described in my email.
> > > > Could someone explain me how and why it is behaving different from
> > > > my expectation?
> > > 
> > > It looks like a bug to me. Testing with this test app here, I can see
> > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > that's unexpected for a v6only socket. As is, it's the server saying
> > > "I'm available at these other addresses too, but not."
> > 
> > Does it even make sense to mix IPv4 and IPv6 addresses on the same
> > connection?
> > I don't remember ever seeing both types of address in a message,
> > but may not have looked.
> 
> That's an interesting question.  Do the RFCs say anything?  I would
> assume it was ok unless ipv6only was set.
> 
> > 
> > I also wonder whether the connection should be dropped for an error
> > response on a path that has never been validated.
> 
> That actually bothered me a bit more.  Shouldn't it stay up if any path
> is up?  That's kind of the whole point of multihoming.

Michael explained it on the other email. What he described is what I
observed in my tests.

> 
> > 
> > OTOH the whole 'multi-homing' part of SCTP sucks.
> 
> I don't think so.
> 
> > The IP addresses a server needs to bind to depend on where the
> > incoming connection will come from.
> > A local connection may be able to use a 192.168.x.x address
> > but a remote connection must not - as it may be defined locally
> > at the remote system.
> > But both connections can come into the public (routable) address.
> > We have to tell customers to explicitly configure the local IP
> > addresses - which means the application has to know what they are.
> > Fortunately these apps are pretty static - usually M3UA.
> 
> Umm, no,  If you have a private address, it better be behind a firewall,
> and the firewall should handle rewriting the packet to fix the addresses.
> 
> It doesn't appear that Linux netfilter does this.  There is a TODO in
> the code for this.  But that's how it *should* work.

Right, we don't support SCTP aware NAT [1].

1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04

  Marcelo

> 
> -corey
> 
> > 
> > 	David
> > 
> > -
> > Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> > Registration No: 1397386 (Wales)
> > 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 21:21               ` 'Marcelo Ricardo Leitner'
  0 siblings, 0 replies; 55+ messages in thread
From: 'Marcelo Ricardo Leitner' @ 2020-06-23 21:21 UTC (permalink / raw)
  To: Corey Minyard
  Cc: David Laight, Michael Tuexen, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> > From: Marcelo Ricardo Leitner
> > > Sent: 22 June 2020 19:33
> > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > > On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > >
> > > > > On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > >> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > >>>
> > > > >>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > >>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > >>> then I make a connection to it using ::1, the connection will drop after
> > > > >>> 2.5 seconds with an ECONNRESET error.
> > > > >>>
> > > > >>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > >>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > >>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > >>> I tried on an ARM system and x86_64.
> > > > >>>
> > > > >>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > >>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > >>> Basically, compile the following code:
> > > > >> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > >> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > >> bind any specific addresses ). Then after the connection is created,
> > > > >> the client will send HB on the v4 paths to the server. The server
> > > > >> will abort the connection, as it can't support v4.
> > > > >>
> > > > >> So you can work around it by either:
> > > > >>
> > > > >>  - set IPV6_V6ONLY on client side.
> > > > >>
> > > > >> or
> > > > >>
> > > > >>  - bind to the specific v6 addresses on the client side.
> > > > >>
> > > > >> I don't see RFC said something about this.
> > > > >> So it may not be a good idea to change the current behaviour
> > > > >> to not establish the connection in this case, which may cause regression.
> > > > >
> > > > > Ok, I understand this.  It's a little strange, but I see why it works
> > > > > this way.
> > > > I don't. I would expect it to work as I described in my email.
> > > > Could someone explain me how and why it is behaving different from
> > > > my expectation?
> > > 
> > > It looks like a bug to me. Testing with this test app here, I can see
> > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > that's unexpected for a v6only socket. As is, it's the server saying
> > > "I'm available at these other addresses too, but not."
> > 
> > Does it even make sense to mix IPv4 and IPv6 addresses on the same
> > connection?
> > I don't remember ever seeing both types of address in a message,
> > but may not have looked.
> 
> That's an interesting question.  Do the RFCs say anything?  I would
> assume it was ok unless ipv6only was set.
> 
> > 
> > I also wonder whether the connection should be dropped for an error
> > response on a path that has never been validated.
> 
> That actually bothered me a bit more.  Shouldn't it stay up if any path
> is up?  That's kind of the whole point of multihoming.

Michael explained it on the other email. What he described is what I
observed in my tests.

> 
> > 
> > OTOH the whole 'multi-homing' part of SCTP sucks.
> 
> I don't think so.
> 
> > The IP addresses a server needs to bind to depend on where the
> > incoming connection will come from.
> > A local connection may be able to use a 192.168.x.x address
> > but a remote connection must not - as it may be defined locally
> > at the remote system.
> > But both connections can come into the public (routable) address.
> > We have to tell customers to explicitly configure the local IP
> > addresses - which means the application has to know what they are.
> > Fortunately these apps are pretty static - usually M3UA.
> 
> Umm, no,  If you have a private address, it better be behind a firewall,
> and the firewall should handle rewriting the packet to fix the addresses.
> 
> It doesn't appear that Linux netfilter does this.  There is a TODO in
> the code for this.  But that's how it *should* work.

Right, we don't support SCTP aware NAT [1].

1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04

  Marcelo

> 
> -corey
> 
> > 
> > 	David
> > 
> > -
> > Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> > Registration No: 1397386 (Wales)
> > 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 21:21               ` 'Marcelo Ricardo Leitner'
@ 2020-06-23 21:24                 ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 21:24 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>> From: Marcelo Ricardo Leitner
>>>> Sent: 22 June 2020 19:33
>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>> 
>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>> 
>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>> 
>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>> 
>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>> Basically, compile the following code:
>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>> will abort the connection, as it can't support v4.
>>>>>>> 
>>>>>>> So you can work around it by either:
>>>>>>> 
>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>> 
>>>>>>> or
>>>>>>> 
>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>> 
>>>>>>> I don't see RFC said something about this.
>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>> 
>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>> this way.
>>>>> I don't. I would expect it to work as I described in my email.
>>>>> Could someone explain me how and why it is behaving different from
>>>>> my expectation?
>>>> 
>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>> "I'm available at these other addresses too, but not."
>>> 
>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>> connection?
>>> I don't remember ever seeing both types of address in a message,
>>> but may not have looked.
>> 
>> That's an interesting question.  Do the RFCs say anything?  I would
>> assume it was ok unless ipv6only was set.
>> 
>>> 
>>> I also wonder whether the connection should be dropped for an error
>>> response on a path that has never been validated.
>> 
>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>> is up?  That's kind of the whole point of multihoming.
> 
> Michael explained it on the other email. What he described is what I
> observed in my tests.
> 
>> 
>>> 
>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>> 
>> I don't think so.
>> 
>>> The IP addresses a server needs to bind to depend on where the
>>> incoming connection will come from.
>>> A local connection may be able to use a 192.168.x.x address
>>> but a remote connection must not - as it may be defined locally
>>> at the remote system.
>>> But both connections can come into the public (routable) address.
>>> We have to tell customers to explicitly configure the local IP
>>> addresses - which means the application has to know what they are.
>>> Fortunately these apps are pretty static - usually M3UA.
>> 
>> Umm, no,  If you have a private address, it better be behind a firewall,
>> and the firewall should handle rewriting the packet to fix the addresses.
>> 
>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>> the code for this.  But that's how it *should* work.
> 
> Right, we don't support SCTP aware NAT [1].
> 
> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16

Another possibility for NAT traversal is UDP encapsulation...

Best regards
Michael
> 
>  Marcelo
> 
>> 
>> -corey
>> 
>>> 
>>> 	David
>>> 
>>> -
>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>> Registration No: 1397386 (Wales)
>>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 21:24                 ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 21:24 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>> From: Marcelo Ricardo Leitner
>>>> Sent: 22 June 2020 19:33
>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>> 
>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>> 
>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>> 
>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>> 
>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>> Basically, compile the following code:
>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>> will abort the connection, as it can't support v4.
>>>>>>> 
>>>>>>> So you can work around it by either:
>>>>>>> 
>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>> 
>>>>>>> or
>>>>>>> 
>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>> 
>>>>>>> I don't see RFC said something about this.
>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>> 
>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>> this way.
>>>>> I don't. I would expect it to work as I described in my email.
>>>>> Could someone explain me how and why it is behaving different from
>>>>> my expectation?
>>>> 
>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>> "I'm available at these other addresses too, but not."
>>> 
>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>> connection?
>>> I don't remember ever seeing both types of address in a message,
>>> but may not have looked.
>> 
>> That's an interesting question.  Do the RFCs say anything?  I would
>> assume it was ok unless ipv6only was set.
>> 
>>> 
>>> I also wonder whether the connection should be dropped for an error
>>> response on a path that has never been validated.
>> 
>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>> is up?  That's kind of the whole point of multihoming.
> 
> Michael explained it on the other email. What he described is what I
> observed in my tests.
> 
>> 
>>> 
>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>> 
>> I don't think so.
>> 
>>> The IP addresses a server needs to bind to depend on where the
>>> incoming connection will come from.
>>> A local connection may be able to use a 192.168.x.x address
>>> but a remote connection must not - as it may be defined locally
>>> at the remote system.
>>> But both connections can come into the public (routable) address.
>>> We have to tell customers to explicitly configure the local IP
>>> addresses - which means the application has to know what they are.
>>> Fortunately these apps are pretty static - usually M3UA.
>> 
>> Umm, no,  If you have a private address, it better be behind a firewall,
>> and the firewall should handle rewriting the packet to fix the addresses.
>> 
>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>> the code for this.  But that's how it *should* work.
> 
> Right, we don't support SCTP aware NAT [1].
> 
> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16

Another possibility for NAT traversal is UDP encapsulation...

Best regards
Michael
> 
>  Marcelo
> 
>> 
>> -corey
>> 
>>> 
>>> 	David
>>> 
>>> -
>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>> Registration No: 1397386 (Wales)
>>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 21:24                 ` Michael Tuexen
@ 2020-06-23 21:31                   ` Marcelo Ricardo Leitner
  -1 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-23 21:31 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
> > On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > 
> > On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> >> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> >>> From: Marcelo Ricardo Leitner
> >>>> Sent: 22 June 2020 19:33
> >>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>>>> 
> >>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>> 
> >>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>>>> 
> >>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>>>>> I tried on an ARM system and x86_64.
> >>>>>>>> 
> >>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>>>>> Basically, compile the following code:
> >>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>>>>> bind any specific addresses ). Then after the connection is created,
> >>>>>>> the client will send HB on the v4 paths to the server. The server
> >>>>>>> will abort the connection, as it can't support v4.
> >>>>>>> 
> >>>>>>> So you can work around it by either:
> >>>>>>> 
> >>>>>>> - set IPV6_V6ONLY on client side.
> >>>>>>> 
> >>>>>>> or
> >>>>>>> 
> >>>>>>> - bind to the specific v6 addresses on the client side.
> >>>>>>> 
> >>>>>>> I don't see RFC said something about this.
> >>>>>>> So it may not be a good idea to change the current behaviour
> >>>>>>> to not establish the connection in this case, which may cause regression.
> >>>>>> 
> >>>>>> Ok, I understand this.  It's a little strange, but I see why it works
> >>>>>> this way.
> >>>>> I don't. I would expect it to work as I described in my email.
> >>>>> Could someone explain me how and why it is behaving different from
> >>>>> my expectation?
> >>>> 
> >>>> It looks like a bug to me. Testing with this test app here, I can see
> >>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> >>>> that's unexpected for a v6only socket. As is, it's the server saying
> >>>> "I'm available at these other addresses too, but not."
> >>> 
> >>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> >>> connection?
> >>> I don't remember ever seeing both types of address in a message,
> >>> but may not have looked.
> >> 
> >> That's an interesting question.  Do the RFCs say anything?  I would
> >> assume it was ok unless ipv6only was set.
> >> 
> >>> 
> >>> I also wonder whether the connection should be dropped for an error
> >>> response on a path that has never been validated.
> >> 
> >> That actually bothered me a bit more.  Shouldn't it stay up if any path
> >> is up?  That's kind of the whole point of multihoming.
> > 
> > Michael explained it on the other email. What he described is what I
> > observed in my tests.
> > 
> >> 
> >>> 
> >>> OTOH the whole 'multi-homing' part of SCTP sucks.
> >> 
> >> I don't think so.
> >> 
> >>> The IP addresses a server needs to bind to depend on where the
> >>> incoming connection will come from.
> >>> A local connection may be able to use a 192.168.x.x address
> >>> but a remote connection must not - as it may be defined locally
> >>> at the remote system.
> >>> But both connections can come into the public (routable) address.
> >>> We have to tell customers to explicitly configure the local IP
> >>> addresses - which means the application has to know what they are.
> >>> Fortunately these apps are pretty static - usually M3UA.
> >> 
> >> Umm, no,  If you have a private address, it better be behind a firewall,
> >> and the firewall should handle rewriting the packet to fix the addresses.
> >> 
> >> It doesn't appear that Linux netfilter does this.  There is a TODO in
> >> the code for this.  But that's how it *should* work.
> > 
> > Right, we don't support SCTP aware NAT [1].
> > 
> > 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16

Thanks!

> 
> Another possibility for NAT traversal is UDP encapsulation...

Also not supported.. :-]

Best regards,
Marcelo

> 
> Best regards
> Michael
> > 
> >  Marcelo
> > 
> >> 
> >> -corey
> >> 
> >>> 
> >>> 	David
> >>> 
> >>> -
> >>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> >>> Registration No: 1397386 (Wales)
> >>> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 21:31                   ` Marcelo Ricardo Leitner
  0 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-23 21:31 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
> > On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > 
> > On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> >> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> >>> From: Marcelo Ricardo Leitner
> >>>> Sent: 22 June 2020 19:33
> >>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>>>> 
> >>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>> 
> >>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>>>> 
> >>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>>>>> I tried on an ARM system and x86_64.
> >>>>>>>> 
> >>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>>>>> Basically, compile the following code:
> >>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>>>>> bind any specific addresses ). Then after the connection is created,
> >>>>>>> the client will send HB on the v4 paths to the server. The server
> >>>>>>> will abort the connection, as it can't support v4.
> >>>>>>> 
> >>>>>>> So you can work around it by either:
> >>>>>>> 
> >>>>>>> - set IPV6_V6ONLY on client side.
> >>>>>>> 
> >>>>>>> or
> >>>>>>> 
> >>>>>>> - bind to the specific v6 addresses on the client side.
> >>>>>>> 
> >>>>>>> I don't see RFC said something about this.
> >>>>>>> So it may not be a good idea to change the current behaviour
> >>>>>>> to not establish the connection in this case, which may cause regression.
> >>>>>> 
> >>>>>> Ok, I understand this.  It's a little strange, but I see why it works
> >>>>>> this way.
> >>>>> I don't. I would expect it to work as I described in my email.
> >>>>> Could someone explain me how and why it is behaving different from
> >>>>> my expectation?
> >>>> 
> >>>> It looks like a bug to me. Testing with this test app here, I can see
> >>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> >>>> that's unexpected for a v6only socket. As is, it's the server saying
> >>>> "I'm available at these other addresses too, but not."
> >>> 
> >>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> >>> connection?
> >>> I don't remember ever seeing both types of address in a message,
> >>> but may not have looked.
> >> 
> >> That's an interesting question.  Do the RFCs say anything?  I would
> >> assume it was ok unless ipv6only was set.
> >> 
> >>> 
> >>> I also wonder whether the connection should be dropped for an error
> >>> response on a path that has never been validated.
> >> 
> >> That actually bothered me a bit more.  Shouldn't it stay up if any path
> >> is up?  That's kind of the whole point of multihoming.
> > 
> > Michael explained it on the other email. What he described is what I
> > observed in my tests.
> > 
> >> 
> >>> 
> >>> OTOH the whole 'multi-homing' part of SCTP sucks.
> >> 
> >> I don't think so.
> >> 
> >>> The IP addresses a server needs to bind to depend on where the
> >>> incoming connection will come from.
> >>> A local connection may be able to use a 192.168.x.x address
> >>> but a remote connection must not - as it may be defined locally
> >>> at the remote system.
> >>> But both connections can come into the public (routable) address.
> >>> We have to tell customers to explicitly configure the local IP
> >>> addresses - which means the application has to know what they are.
> >>> Fortunately these apps are pretty static - usually M3UA.
> >> 
> >> Umm, no,  If you have a private address, it better be behind a firewall,
> >> and the firewall should handle rewriting the packet to fix the addresses.
> >> 
> >> It doesn't appear that Linux netfilter does this.  There is a TODO in
> >> the code for this.  But that's how it *should* work.
> > 
> > Right, we don't support SCTP aware NAT [1].
> > 
> > 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16

Thanks!

> 
> Another possibility for NAT traversal is UDP encapsulation...

Also not supported.. :-]

Best regards,
Marcelo

> 
> Best regards
> Michael
> > 
> >  Marcelo
> > 
> >> 
> >> -corey
> >> 
> >>> 
> >>> 	David
> >>> 
> >>> -
> >>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> >>> Registration No: 1397386 (Wales)
> >>> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 21:31                   ` Marcelo Ricardo Leitner
@ 2020-06-23 21:48                     ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 21:48 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
>>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>> 
>>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>>>> From: Marcelo Ricardo Leitner
>>>>>> Sent: 22 June 2020 19:33
>>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>>>> 
>>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>>>> 
>>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>>>> 
>>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>>>> Basically, compile the following code:
>>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>>>> will abort the connection, as it can't support v4.
>>>>>>>>> 
>>>>>>>>> So you can work around it by either:
>>>>>>>>> 
>>>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>>>> 
>>>>>>>>> or
>>>>>>>>> 
>>>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>>>> 
>>>>>>>>> I don't see RFC said something about this.
>>>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>>>> 
>>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>>>> this way.
>>>>>>> I don't. I would expect it to work as I described in my email.
>>>>>>> Could someone explain me how and why it is behaving different from
>>>>>>> my expectation?
>>>>>> 
>>>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>>>> "I'm available at these other addresses too, but not."
>>>>> 
>>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>>>> connection?
>>>>> I don't remember ever seeing both types of address in a message,
>>>>> but may not have looked.
>>>> 
>>>> That's an interesting question.  Do the RFCs say anything?  I would
>>>> assume it was ok unless ipv6only was set.
>>>> 
>>>>> 
>>>>> I also wonder whether the connection should be dropped for an error
>>>>> response on a path that has never been validated.
>>>> 
>>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>>>> is up?  That's kind of the whole point of multihoming.
>>> 
>>> Michael explained it on the other email. What he described is what I
>>> observed in my tests.
>>> 
>>>> 
>>>>> 
>>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>>>> 
>>>> I don't think so.
>>>> 
>>>>> The IP addresses a server needs to bind to depend on where the
>>>>> incoming connection will come from.
>>>>> A local connection may be able to use a 192.168.x.x address
>>>>> but a remote connection must not - as it may be defined locally
>>>>> at the remote system.
>>>>> But both connections can come into the public (routable) address.
>>>>> We have to tell customers to explicitly configure the local IP
>>>>> addresses - which means the application has to know what they are.
>>>>> Fortunately these apps are pretty static - usually M3UA.
>>>> 
>>>> Umm, no,  If you have a private address, it better be behind a firewall,
>>>> and the firewall should handle rewriting the packet to fix the addresses.
>>>> 
>>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>>>> the code for this.  But that's how it *should* work.
>>> 
>>> Right, we don't support SCTP aware NAT [1].
>>> 
>>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
>> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
> 
> Thanks!
> 
>> 
>> Another possibility for NAT traversal is UDP encapsulation...
> 
> Also not supported.. :-]
But maybe someone wants to implement it. It is supported by FreeBSD, if you
need a peer for testing. Or the userland stack usrsctp supports it. Then you
do not need root privileges to run it.

Best regards
Michael
> 
> Best regards,
> Marcelo
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Marcelo
>>> 
>>>> 
>>>> -corey
>>>> 
>>>>> 
>>>>> 	David
>>>>> 
>>>>> -
>>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>>>> Registration No: 1397386 (Wales)
>>>>> 
>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-23 21:48                     ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-23 21:48 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: Corey Minyard, David Laight, Xin Long, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> 
> On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
>>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>> 
>>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>>>> From: Marcelo Ricardo Leitner
>>>>>> Sent: 22 June 2020 19:33
>>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>>>> 
>>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>>>> 
>>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>>>> 
>>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>>>> Basically, compile the following code:
>>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>>>> will abort the connection, as it can't support v4.
>>>>>>>>> 
>>>>>>>>> So you can work around it by either:
>>>>>>>>> 
>>>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>>>> 
>>>>>>>>> or
>>>>>>>>> 
>>>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>>>> 
>>>>>>>>> I don't see RFC said something about this.
>>>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>>>> 
>>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>>>> this way.
>>>>>>> I don't. I would expect it to work as I described in my email.
>>>>>>> Could someone explain me how and why it is behaving different from
>>>>>>> my expectation?
>>>>>> 
>>>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>>>> "I'm available at these other addresses too, but not."
>>>>> 
>>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>>>> connection?
>>>>> I don't remember ever seeing both types of address in a message,
>>>>> but may not have looked.
>>>> 
>>>> That's an interesting question.  Do the RFCs say anything?  I would
>>>> assume it was ok unless ipv6only was set.
>>>> 
>>>>> 
>>>>> I also wonder whether the connection should be dropped for an error
>>>>> response on a path that has never been validated.
>>>> 
>>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>>>> is up?  That's kind of the whole point of multihoming.
>>> 
>>> Michael explained it on the other email. What he described is what I
>>> observed in my tests.
>>> 
>>>> 
>>>>> 
>>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>>>> 
>>>> I don't think so.
>>>> 
>>>>> The IP addresses a server needs to bind to depend on where the
>>>>> incoming connection will come from.
>>>>> A local connection may be able to use a 192.168.x.x address
>>>>> but a remote connection must not - as it may be defined locally
>>>>> at the remote system.
>>>>> But both connections can come into the public (routable) address.
>>>>> We have to tell customers to explicitly configure the local IP
>>>>> addresses - which means the application has to know what they are.
>>>>> Fortunately these apps are pretty static - usually M3UA.
>>>> 
>>>> Umm, no,  If you have a private address, it better be behind a firewall,
>>>> and the firewall should handle rewriting the packet to fix the addresses.
>>>> 
>>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>>>> the code for this.  But that's how it *should* work.
>>> 
>>> Right, we don't support SCTP aware NAT [1].
>>> 
>>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
>> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
> 
> Thanks!
> 
>> 
>> Another possibility for NAT traversal is UDP encapsulation...
> 
> Also not supported.. :-]
But maybe someone wants to implement it. It is supported by FreeBSD, if you
need a peer for testing. Or the userland stack usrsctp supports it. Then you
do not need root privileges to run it.

Best regards
Michael
> 
> Best regards,
> Marcelo
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Marcelo
>>> 
>>>> 
>>>> -corey
>>>> 
>>>>> 
>>>>> 	David
>>>>> 
>>>>> -
>>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>>>> Registration No: 1397386 (Wales)
>>>>> 
>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 16:00                   ` Corey Minyard
@ 2020-06-24  6:58                     ` Xin Long
  -1 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-24  6:58 UTC (permalink / raw)
  To: minyard
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Wed, Jun 24, 2020 at 12:00 AM Corey Minyard <minyard@acm.org> wrote:
>
> On Tue, Jun 23, 2020 at 11:40:21PM +0800, Xin Long wrote:
> > On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
> > >
> > > On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > > > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > > > <Michael.Tuexen@lurchi.franken.de> wrote:
> > > > >
> > > > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > > > >
> > > > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > > >>>
> > > > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > > >>>>>
> > > > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > > > >>>>>
> > > > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > > >>>>> I tried on an ARM system and x86_64.
> > > > > >>>>>
> > > > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > > >>>>> Basically, compile the following code:
> > > > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > > >>>> bind any specific addresses ). Then after the connection is created,
> > > > > >>>> the client will send HB on the v4 paths to the server. The server
> > > > > >>>> will abort the connection, as it can't support v4.
> > > > > >>>>
> > > > > >>>> So you can work around it by either:
> > > > > >>>>
> > > > > >>>> - set IPV6_V6ONLY on client side.
> > > > > >>>>
> > > > > >>>> or
> > > > > >>>>
> > > > > >>>> - bind to the specific v6 addresses on the client side.
> > > > > >>>>
> > > > > >>>> I don't see RFC said something about this.
> > > > > >>>> So it may not be a good idea to change the current behaviour
> > > > > >>>> to not establish the connection in this case, which may cause regression.
> > > > > >>>
> > > > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > > > >>> this way.
> > > > > >> I don't. I would expect it to work as I described in my email.
> > > > > >> Could someone explain me how and why it is behaving different from
> > > > > >> my expectation?
> > > > > >
> > > > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > > > "I'm available at these other addresses too, but not."
> > > > > I agree.
> > > > Then we need a fix in sctp_bind_addrs_to_raw():
> > > >
> > > > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > > > struct sctp_bind_addr *bp,
> > > >         addrparms = retval;
> > > >
> > > >         list_for_each_entry(addr, &bp->address_list, list) {
> > > > +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
> > > > +                   (AF_INET == addr->a.sa.sa_family))
> > > > +                       continue;
> > >
> > > This does not compile in the latest mainline.  sk is not defined.
> > > Also, if you could send a normal git patch, that would be easier to
> > > manage.
> > sorry, that was just the code to show the idea.
> >
> > For the compilable one, pls see:
> > https://paste.centos.org/view/49f5ff5a
>
> The kernel community runs on patches.  It's hard to talk about changes
> if you put things in pastbin type of stuff.  Please send full complete
> patches in emails.  I will do that in a moment.
I thought you wanted a temporary patch to run your test.

The final patch still needs some change, like drop the *bp param
even from sctp_make_init().

>
> Anyway, are use sure every bp passed into sctp_bind_addrs_to_raw()
> is &asoc->base.bind_addr?  It's passed in to sctp_make_init() and the
> passed to sctp_bind_addrs_to_raw().  If this is the case, you can remove
> it from the parameters of sctp_make_init().  But I suspect it's passed
> in for a reason.
This is not difficult to track.
path 1:
sctp_sf_do_5_2_6_stale()/sctp_sf_do_prm_asoc()/
sctp_sf_t1_init_timer_expire() ->
  sctp_make_init() -> sctp_bind_addrs_to_raw()

path 2:
sctp_make_init_ack() -> sctp_bind_addrs_to_raw().

If you think there must be a reason for this,
I think it's they may just pass a minimal-structure pointer.

>
> Anyway, I have a patch I have compiled and tested, I will send that.
>
> -corey
>
> >
> > Thanks.
> > >
> > > Thanks,
> > >
> > > -corey
> > >
> > > >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> > > >                 len = af->to_addr_param(&addr->a, &rawaddr);
> > > >                 memcpy(addrparms.v, &rawaddr, len);
> > > >
> > > > >
> > > > > Best regards
> > > > > Michael
> > > > > >
> > > > > > Thanks,
> > > > > > Marcelo
> > > > > >
> > > > > >>
> > > > > >> Best regards
> > > > > >> Michael
> > > > > >>>
> > > > > >>> Thanks,
> > > > > >>>
> > > > > >>> -corey
> > > > > >>>
> > > > > >>>>
> > > > > >>>>>
> > > > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > > > >>>>>
> > > > > >>>>> and run it in one window as a server:
> > > > > >>>>>
> > > > > >>>>> ./sctptest a
> > > > > >>>>>
> > > > > >>>>> (Pass in any option to be the server) and run the following in another
> > > > > >>>>> window as the client:
> > > > > >>>>>
> > > > > >>>>> ./sctptest
> > > > > >>>>>
> > > > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > > > >>>>> there forever.
> > > > > >>>>>
> > > > > >>>>> -corey
> > > > > >>>>>
> > > > > >>>>>
> > > > > >>>>> #include <stdio.h>
> > > > > >>>>> #include <stdbool.h>
> > > > > >>>>> #include <string.h>
> > > > > >>>>> #include <unistd.h>
> > > > > >>>>> #include <fcntl.h>
> > > > > >>>>> #include <sys/select.h>
> > > > > >>>>> #include <arpa/inet.h>
> > > > > >>>>> #include <netinet/sctp.h>
> > > > > >>>>> #include <sys/types.h>
> > > > > >>>>> #include <sys/socket.h>
> > > > > >>>>> #include <netdb.h>
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > > > >>>>>       struct addrinfo **rai)
> > > > > >>>>> {
> > > > > >>>>>   struct addrinfo *ai, hints;
> > > > > >>>>>
> > > > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > > > >>>>>   if (listen)
> > > > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > > > >>>>>       perror("getaddrinfo");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   *rai = ai;
> > > > > >>>>>   return 0;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> waitread(int s)
> > > > > >>>>> {
> > > > > >>>>>   char data[1];
> > > > > >>>>>   ssize_t rv;
> > > > > >>>>>
> > > > > >>>>>   rv = read(s, data, sizeof(data));
> > > > > >>>>>   if (rv == -1) {
> > > > > >>>>>       perror("read");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > > > >>>>>   return 0;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> do_server(void)
> > > > > >>>>> {
> > > > > >>>>>   int err, ls, s, optval;
> > > > > >>>>>   struct addrinfo *ai;
> > > > > >>>>>
> > > > > >>>>>   printf("Server\n");
> > > > > >>>>>
> > > > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > > > >>>>>   if (err)
> > > > > >>>>>       return err;
> > > > > >>>>>
> > > > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > > >>>>>   if (ls == -1) {
> > > > > >>>>>       perror("socket");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   optval = 1;
> > > > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > > > >>>>>                  (void *)&optval, sizeof(optval)) == -1) {
> > > > > >>>>>       perror("setsockopt reuseaddr");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   /* Comment this out and it will work. */
> > > > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > > > >>>>>                  sizeof(optval)) == -1) {
> > > > > >>>>>       perror("setsockopt ipv6 only");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > > > >>>>>   if (err == -1) {
> > > > > >>>>>       perror("bind");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = listen(ls, 5);
> > > > > >>>>>   if (err == -1) {
> > > > > >>>>>       perror("listen");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   s = accept(ls, NULL, NULL);
> > > > > >>>>>   if (s == -1) {
> > > > > >>>>>       perror("accept");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   close(ls);
> > > > > >>>>>
> > > > > >>>>>   err = waitread(s);
> > > > > >>>>>   close(s);
> > > > > >>>>>   return err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> do_client(void)
> > > > > >>>>> {
> > > > > >>>>>   int err, s;
> > > > > >>>>>   struct addrinfo *ai;
> > > > > >>>>>
> > > > > >>>>>   printf("Client\n");
> > > > > >>>>>
> > > > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > > > >>>>>   if (err)
> > > > > >>>>>       return err;
> > > > > >>>>>
> > > > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > > >>>>>   if (s == -1) {
> > > > > >>>>>       perror("socket");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > > > >>>>>   if (err == -1) {
> > > > > >>>>>       perror("connect");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = waitread(s);
> > > > > >>>>>   close(s);
> > > > > >>>>>   return err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> int
> > > > > >>>>> main(int argc, char *argv[])
> > > > > >>>>> {
> > > > > >>>>>   int err;
> > > > > >>>>>
> > > > > >>>>>   if (argc > 1)
> > > > > >>>>>       err = do_server();
> > > > > >>>>>   else
> > > > > >>>>>       err = do_client();
> > > > > >>>>>   return !!err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>
> > > > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-24  6:58                     ` Xin Long
  0 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-24  6:58 UTC (permalink / raw)
  To: minyard
  Cc: Michael Tuexen, Marcelo Ricardo Leitner, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

On Wed, Jun 24, 2020 at 12:00 AM Corey Minyard <minyard@acm.org> wrote:
>
> On Tue, Jun 23, 2020 at 11:40:21PM +0800, Xin Long wrote:
> > On Tue, Jun 23, 2020 at 9:29 PM Corey Minyard <minyard@acm.org> wrote:
> > >
> > > On Tue, Jun 23, 2020 at 06:13:30PM +0800, Xin Long wrote:
> > > > On Tue, Jun 23, 2020 at 2:34 AM Michael Tuexen
> > > > <Michael.Tuexen@lurchi.franken.de> wrote:
> > > > >
> > > > > > On 22. Jun 2020, at 20:32, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> > > > > >
> > > > > > On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> > > > > >>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> > > > > >>>
> > > > > >>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> > > > > >>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> > > > > >>>>>
> > > > > >>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> > > > > >>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> > > > > >>>>> then I make a connection to it using ::1, the connection will drop after
> > > > > >>>>> 2.5 seconds with an ECONNRESET error.
> > > > > >>>>>
> > > > > >>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> > > > > >>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> > > > > >>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> > > > > >>>>> I tried on an ARM system and x86_64.
> > > > > >>>>>
> > > > > >>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> > > > > >>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> > > > > >>>>> Basically, compile the following code:
> > > > > >>>> The code only set IPV6_V6ONLY on server side, so the client side will
> > > > > >>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> > > > > >>>> bind any specific addresses ). Then after the connection is created,
> > > > > >>>> the client will send HB on the v4 paths to the server. The server
> > > > > >>>> will abort the connection, as it can't support v4.
> > > > > >>>>
> > > > > >>>> So you can work around it by either:
> > > > > >>>>
> > > > > >>>> - set IPV6_V6ONLY on client side.
> > > > > >>>>
> > > > > >>>> or
> > > > > >>>>
> > > > > >>>> - bind to the specific v6 addresses on the client side.
> > > > > >>>>
> > > > > >>>> I don't see RFC said something about this.
> > > > > >>>> So it may not be a good idea to change the current behaviour
> > > > > >>>> to not establish the connection in this case, which may cause regression.
> > > > > >>>
> > > > > >>> Ok, I understand this.  It's a little strange, but I see why it works
> > > > > >>> this way.
> > > > > >> I don't. I would expect it to work as I described in my email.
> > > > > >> Could someone explain me how and why it is behaving different from
> > > > > >> my expectation?
> > > > > >
> > > > > > It looks like a bug to me. Testing with this test app here, I can see
> > > > > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > > > > that's unexpected for a v6only socket. As is, it's the server saying
> > > > > > "I'm available at these other addresses too, but not."
> > > > > I agree.
> > > > Then we need a fix in sctp_bind_addrs_to_raw():
> > > >
> > > > @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> > > > struct sctp_bind_addr *bp,
> > > >         addrparms = retval;
> > > >
> > > >         list_for_each_entry(addr, &bp->address_list, list) {
> > > > +               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
> > > > +                   (AF_INET = addr->a.sa.sa_family))
> > > > +                       continue;
> > >
> > > This does not compile in the latest mainline.  sk is not defined.
> > > Also, if you could send a normal git patch, that would be easier to
> > > manage.
> > sorry, that was just the code to show the idea.
> >
> > For the compilable one, pls see:
> > https://paste.centos.org/view/49f5ff5a
>
> The kernel community runs on patches.  It's hard to talk about changes
> if you put things in pastbin type of stuff.  Please send full complete
> patches in emails.  I will do that in a moment.
I thought you wanted a temporary patch to run your test.

The final patch still needs some change, like drop the *bp param
even from sctp_make_init().

>
> Anyway, are use sure every bp passed into sctp_bind_addrs_to_raw()
> is &asoc->base.bind_addr?  It's passed in to sctp_make_init() and the
> passed to sctp_bind_addrs_to_raw().  If this is the case, you can remove
> it from the parameters of sctp_make_init().  But I suspect it's passed
> in for a reason.
This is not difficult to track.
path 1:
sctp_sf_do_5_2_6_stale()/sctp_sf_do_prm_asoc()/
sctp_sf_t1_init_timer_expire() ->
  sctp_make_init() -> sctp_bind_addrs_to_raw()

path 2:
sctp_make_init_ack() -> sctp_bind_addrs_to_raw().

If you think there must be a reason for this,
I think it's they may just pass a minimal-structure pointer.

>
> Anyway, I have a patch I have compiled and tested, I will send that.
>
> -corey
>
> >
> > Thanks.
> > >
> > > Thanks,
> > >
> > > -corey
> > >
> > > >                 af = sctp_get_af_specific(addr->a.v4.sin_family);
> > > >                 len = af->to_addr_param(&addr->a, &rawaddr);
> > > >                 memcpy(addrparms.v, &rawaddr, len);
> > > >
> > > > >
> > > > > Best regards
> > > > > Michael
> > > > > >
> > > > > > Thanks,
> > > > > > Marcelo
> > > > > >
> > > > > >>
> > > > > >> Best regards
> > > > > >> Michael
> > > > > >>>
> > > > > >>> Thanks,
> > > > > >>>
> > > > > >>> -corey
> > > > > >>>
> > > > > >>>>
> > > > > >>>>>
> > > > > >>>>> gcc -g -o sctptest -Wall sctptest.c
> > > > > >>>>>
> > > > > >>>>> and run it in one window as a server:
> > > > > >>>>>
> > > > > >>>>> ./sctptest a
> > > > > >>>>>
> > > > > >>>>> (Pass in any option to be the server) and run the following in another
> > > > > >>>>> window as the client:
> > > > > >>>>>
> > > > > >>>>> ./sctptest
> > > > > >>>>>
> > > > > >>>>> It disconnects after about 2.5 seconds.  If it works, it should just sit
> > > > > >>>>> there forever.
> > > > > >>>>>
> > > > > >>>>> -corey
> > > > > >>>>>
> > > > > >>>>>
> > > > > >>>>> #include <stdio.h>
> > > > > >>>>> #include <stdbool.h>
> > > > > >>>>> #include <string.h>
> > > > > >>>>> #include <unistd.h>
> > > > > >>>>> #include <fcntl.h>
> > > > > >>>>> #include <sys/select.h>
> > > > > >>>>> #include <arpa/inet.h>
> > > > > >>>>> #include <netinet/sctp.h>
> > > > > >>>>> #include <sys/types.h>
> > > > > >>>>> #include <sys/socket.h>
> > > > > >>>>> #include <netdb.h>
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> getaddr(const char *addr, const char *port, bool listen,
> > > > > >>>>>       struct addrinfo **rai)
> > > > > >>>>> {
> > > > > >>>>>   struct addrinfo *ai, hints;
> > > > > >>>>>
> > > > > >>>>>   memset(&hints, 0, sizeof(hints));
> > > > > >>>>>   hints.ai_flags = AI_ADDRCONFIG;
> > > > > >>>>>   if (listen)
> > > > > >>>>>       hints.ai_flags |= AI_PASSIVE;
> > > > > >>>>>   hints.ai_family = AF_UNSPEC;
> > > > > >>>>>   hints.ai_socktype = SOCK_STREAM;
> > > > > >>>>>   hints.ai_protocol = IPPROTO_SCTP;
> > > > > >>>>>   if (getaddrinfo(addr, port, &hints, &ai)) {
> > > > > >>>>>       perror("getaddrinfo");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   *rai = ai;
> > > > > >>>>>   return 0;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> waitread(int s)
> > > > > >>>>> {
> > > > > >>>>>   char data[1];
> > > > > >>>>>   ssize_t rv;
> > > > > >>>>>
> > > > > >>>>>   rv = read(s, data, sizeof(data));
> > > > > >>>>>   if (rv = -1) {
> > > > > >>>>>       perror("read");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>   printf("Read %d bytes\n", (int) rv);
> > > > > >>>>>   return 0;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> do_server(void)
> > > > > >>>>> {
> > > > > >>>>>   int err, ls, s, optval;
> > > > > >>>>>   struct addrinfo *ai;
> > > > > >>>>>
> > > > > >>>>>   printf("Server\n");
> > > > > >>>>>
> > > > > >>>>>   err = getaddr("::", "3023", true, &ai);
> > > > > >>>>>   if (err)
> > > > > >>>>>       return err;
> > > > > >>>>>
> > > > > >>>>>   ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > > >>>>>   if (ls = -1) {
> > > > > >>>>>       perror("socket");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   optval = 1;
> > > > > >>>>>   if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR,
> > > > > >>>>>                  (void *)&optval, sizeof(optval)) = -1) {
> > > > > >>>>>       perror("setsockopt reuseaddr");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   /* Comment this out and it will work. */
> > > > > >>>>>   if (setsockopt(ls, IPPROTO_IPV6, IPV6_V6ONLY, &optval,
> > > > > >>>>>                  sizeof(optval)) = -1) {
> > > > > >>>>>       perror("setsockopt ipv6 only");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = bind(ls, ai->ai_addr, ai->ai_addrlen);
> > > > > >>>>>   if (err = -1) {
> > > > > >>>>>       perror("bind");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = listen(ls, 5);
> > > > > >>>>>   if (err = -1) {
> > > > > >>>>>       perror("listen");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   s = accept(ls, NULL, NULL);
> > > > > >>>>>   if (s = -1) {
> > > > > >>>>>       perror("accept");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   close(ls);
> > > > > >>>>>
> > > > > >>>>>   err = waitread(s);
> > > > > >>>>>   close(s);
> > > > > >>>>>   return err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> static int
> > > > > >>>>> do_client(void)
> > > > > >>>>> {
> > > > > >>>>>   int err, s;
> > > > > >>>>>   struct addrinfo *ai;
> > > > > >>>>>
> > > > > >>>>>   printf("Client\n");
> > > > > >>>>>
> > > > > >>>>>   err = getaddr("::1", "3023", false, &ai);
> > > > > >>>>>   if (err)
> > > > > >>>>>       return err;
> > > > > >>>>>
> > > > > >>>>>   s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
> > > > > >>>>>   if (s = -1) {
> > > > > >>>>>       perror("socket");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = connect(s, ai->ai_addr, ai->ai_addrlen);
> > > > > >>>>>   if (err = -1) {
> > > > > >>>>>       perror("connect");
> > > > > >>>>>       return -1;
> > > > > >>>>>   }
> > > > > >>>>>
> > > > > >>>>>   err = waitread(s);
> > > > > >>>>>   close(s);
> > > > > >>>>>   return err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>>>> int
> > > > > >>>>> main(int argc, char *argv[])
> > > > > >>>>> {
> > > > > >>>>>   int err;
> > > > > >>>>>
> > > > > >>>>>   if (argc > 1)
> > > > > >>>>>       err = do_server();
> > > > > >>>>>   else
> > > > > >>>>>       err = do_client();
> > > > > >>>>>   return !!err;
> > > > > >>>>> }
> > > > > >>>>>
> > > > > >>
> > > > >

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-23 21:48                     ` Michael Tuexen
@ 2020-06-24  7:25                       ` Xin Long
  -1 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-24  7:25 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Marcelo Ricardo Leitner, Corey Minyard, David Laight,
	Vlad Yasevich, Neil Horman, linux-sctp, LKML

On Wed, Jun 24, 2020 at 5:48 AM Michael Tuexen
<michael.tuexen@lurchi.franken.de> wrote:
>
> > On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >
> > On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
> >>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >>>
> >>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> >>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> >>>>> From: Marcelo Ricardo Leitner
> >>>>>> Sent: 22 June 2020 19:33
> >>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>>
> >>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>>>>
> >>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>>>>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>>>>>>
> >>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>>>>>>> I tried on an ARM system and x86_64.
> >>>>>>>>>>
> >>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>>>>>>> Basically, compile the following code:
> >>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>>>>>>> bind any specific addresses ). Then after the connection is created,
> >>>>>>>>> the client will send HB on the v4 paths to the server. The server
> >>>>>>>>> will abort the connection, as it can't support v4.
> >>>>>>>>>
> >>>>>>>>> So you can work around it by either:
> >>>>>>>>>
> >>>>>>>>> - set IPV6_V6ONLY on client side.
> >>>>>>>>>
> >>>>>>>>> or
> >>>>>>>>>
> >>>>>>>>> - bind to the specific v6 addresses on the client side.
> >>>>>>>>>
> >>>>>>>>> I don't see RFC said something about this.
> >>>>>>>>> So it may not be a good idea to change the current behaviour
> >>>>>>>>> to not establish the connection in this case, which may cause regression.
> >>>>>>>>
> >>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
> >>>>>>>> this way.
> >>>>>>> I don't. I would expect it to work as I described in my email.
> >>>>>>> Could someone explain me how and why it is behaving different from
> >>>>>>> my expectation?
> >>>>>>
> >>>>>> It looks like a bug to me. Testing with this test app here, I can see
> >>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> >>>>>> that's unexpected for a v6only socket. As is, it's the server saying
> >>>>>> "I'm available at these other addresses too, but not."
> >>>>>
> >>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> >>>>> connection?
> >>>>> I don't remember ever seeing both types of address in a message,
> >>>>> but may not have looked.
> >>>>
> >>>> That's an interesting question.  Do the RFCs say anything?  I would
> >>>> assume it was ok unless ipv6only was set.
> >>>>
> >>>>>
> >>>>> I also wonder whether the connection should be dropped for an error
> >>>>> response on a path that has never been validated.
> >>>>
> >>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
> >>>> is up?  That's kind of the whole point of multihoming.
> >>>
> >>> Michael explained it on the other email. What he described is what I
> >>> observed in my tests.
> >>>
> >>>>
> >>>>>
> >>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
> >>>>
> >>>> I don't think so.
> >>>>
> >>>>> The IP addresses a server needs to bind to depend on where the
> >>>>> incoming connection will come from.
> >>>>> A local connection may be able to use a 192.168.x.x address
> >>>>> but a remote connection must not - as it may be defined locally
> >>>>> at the remote system.
> >>>>> But both connections can come into the public (routable) address.
> >>>>> We have to tell customers to explicitly configure the local IP
> >>>>> addresses - which means the application has to know what they are.
> >>>>> Fortunately these apps are pretty static - usually M3UA.
> >>>>
> >>>> Umm, no,  If you have a private address, it better be behind a firewall,
> >>>> and the firewall should handle rewriting the packet to fix the addresses.
> >>>>
> >>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
> >>>> the code for this.  But that's how it *should* work.
> >>>
> >>> Right, we don't support SCTP aware NAT [1].
> >>>
> >>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
> >> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
> >
> > Thanks!
> >
> >>
> >> Another possibility for NAT traversal is UDP encapsulation...
> >
> > Also not supported.. :-]
> But maybe someone wants to implement it. It is supported by FreeBSD, if you
> need a peer for testing. Or the userland stack usrsctp supports it. Then you
> do not need root privileges to run it.
You mean SCTP_REMOTE_UDP_ENCAPS_PORT sockopt, right?
We have this in our to-do list. I mixed rfc6951 with the userland one.
Will prioritize this feature. Thanks.

>
> Best regards
> Michael
> >
> > Best regards,
> > Marcelo
> >
> >>
> >> Best regards
> >> Michael
> >>>
> >>> Marcelo
> >>>
> >>>>
> >>>> -corey
> >>>>
> >>>>>
> >>>>>   David
> >>>>>
> >>>>> -
> >>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> >>>>> Registration No: 1397386 (Wales)
> >>>>>
> >>
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-24  7:25                       ` Xin Long
  0 siblings, 0 replies; 55+ messages in thread
From: Xin Long @ 2020-06-24  7:25 UTC (permalink / raw)
  To: Michael Tuexen
  Cc: Marcelo Ricardo Leitner, Corey Minyard, David Laight,
	Vlad Yasevich, Neil Horman, linux-sctp, LKML

On Wed, Jun 24, 2020 at 5:48 AM Michael Tuexen
<michael.tuexen@lurchi.franken.de> wrote:
>
> > On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >
> > On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
> >>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> >>>
> >>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
> >>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
> >>>>> From: Marcelo Ricardo Leitner
> >>>>>> Sent: 22 June 2020 19:33
> >>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
> >>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>>
> >>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
> >>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
> >>>>>>>>>>
> >>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
> >>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
> >>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
> >>>>>>>>>> 2.5 seconds with an ECONNRESET error.
> >>>>>>>>>>
> >>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
> >>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
> >>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
> >>>>>>>>>> I tried on an ARM system and x86_64.
> >>>>>>>>>>
> >>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
> >>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
> >>>>>>>>>> Basically, compile the following code:
> >>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
> >>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
> >>>>>>>>> bind any specific addresses ). Then after the connection is created,
> >>>>>>>>> the client will send HB on the v4 paths to the server. The server
> >>>>>>>>> will abort the connection, as it can't support v4.
> >>>>>>>>>
> >>>>>>>>> So you can work around it by either:
> >>>>>>>>>
> >>>>>>>>> - set IPV6_V6ONLY on client side.
> >>>>>>>>>
> >>>>>>>>> or
> >>>>>>>>>
> >>>>>>>>> - bind to the specific v6 addresses on the client side.
> >>>>>>>>>
> >>>>>>>>> I don't see RFC said something about this.
> >>>>>>>>> So it may not be a good idea to change the current behaviour
> >>>>>>>>> to not establish the connection in this case, which may cause regression.
> >>>>>>>>
> >>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
> >>>>>>>> this way.
> >>>>>>> I don't. I would expect it to work as I described in my email.
> >>>>>>> Could someone explain me how and why it is behaving different from
> >>>>>>> my expectation?
> >>>>>>
> >>>>>> It looks like a bug to me. Testing with this test app here, I can see
> >>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> >>>>>> that's unexpected for a v6only socket. As is, it's the server saying
> >>>>>> "I'm available at these other addresses too, but not."
> >>>>>
> >>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
> >>>>> connection?
> >>>>> I don't remember ever seeing both types of address in a message,
> >>>>> but may not have looked.
> >>>>
> >>>> That's an interesting question.  Do the RFCs say anything?  I would
> >>>> assume it was ok unless ipv6only was set.
> >>>>
> >>>>>
> >>>>> I also wonder whether the connection should be dropped for an error
> >>>>> response on a path that has never been validated.
> >>>>
> >>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
> >>>> is up?  That's kind of the whole point of multihoming.
> >>>
> >>> Michael explained it on the other email. What he described is what I
> >>> observed in my tests.
> >>>
> >>>>
> >>>>>
> >>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
> >>>>
> >>>> I don't think so.
> >>>>
> >>>>> The IP addresses a server needs to bind to depend on where the
> >>>>> incoming connection will come from.
> >>>>> A local connection may be able to use a 192.168.x.x address
> >>>>> but a remote connection must not - as it may be defined locally
> >>>>> at the remote system.
> >>>>> But both connections can come into the public (routable) address.
> >>>>> We have to tell customers to explicitly configure the local IP
> >>>>> addresses - which means the application has to know what they are.
> >>>>> Fortunately these apps are pretty static - usually M3UA.
> >>>>
> >>>> Umm, no,  If you have a private address, it better be behind a firewall,
> >>>> and the firewall should handle rewriting the packet to fix the addresses.
> >>>>
> >>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
> >>>> the code for this.  But that's how it *should* work.
> >>>
> >>> Right, we don't support SCTP aware NAT [1].
> >>>
> >>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
> >> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
> >
> > Thanks!
> >
> >>
> >> Another possibility for NAT traversal is UDP encapsulation...
> >
> > Also not supported.. :-]
> But maybe someone wants to implement it. It is supported by FreeBSD, if you
> need a peer for testing. Or the userland stack usrsctp supports it. Then you
> do not need root privileges to run it.
You mean SCTP_REMOTE_UDP_ENCAPS_PORT sockopt, right?
We have this in our to-do list. I mixed rfc6951 with the userland one.
Will prioritize this feature. Thanks.

>
> Best regards
> Michael
> >
> > Best regards,
> > Marcelo
> >
> >>
> >> Best regards
> >> Michael
> >>>
> >>> Marcelo
> >>>
> >>>>
> >>>> -corey
> >>>>
> >>>>>
> >>>>>   David
> >>>>>
> >>>>> -
> >>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> >>>>> Registration No: 1397386 (Wales)
> >>>>>
> >>
>

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-24  7:25                       ` Xin Long
@ 2020-06-24  9:18                         ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-24  9:18 UTC (permalink / raw)
  To: Xin Long
  Cc: Marcelo Ricardo Leitner, Corey Minyard, David Laight,
	Vlad Yasevich, Neil Horman, linux-sctp, LKML

> On 24. Jun 2020, at 09:25, Xin Long <lucien.xin@gmail.com> wrote:
> 
> On Wed, Jun 24, 2020 at 5:48 AM Michael Tuexen
> <michael.tuexen@lurchi.franken.de> wrote:
>> 
>>> On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>> 
>>> On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
>>>>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>>>> 
>>>>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>>>>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>>>>>> From: Marcelo Ricardo Leitner
>>>>>>>> Sent: 22 June 2020 19:33
>>>>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>>>>>> 
>>>>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>>>>>> 
>>>>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>>>>>> Basically, compile the following code:
>>>>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>>>>>> will abort the connection, as it can't support v4.
>>>>>>>>>>> 
>>>>>>>>>>> So you can work around it by either:
>>>>>>>>>>> 
>>>>>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>>>>>> 
>>>>>>>>>>> or
>>>>>>>>>>> 
>>>>>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>>>>>> 
>>>>>>>>>>> I don't see RFC said something about this.
>>>>>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>>>>>> 
>>>>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>>>>>> this way.
>>>>>>>>> I don't. I would expect it to work as I described in my email.
>>>>>>>>> Could someone explain me how and why it is behaving different from
>>>>>>>>> my expectation?
>>>>>>>> 
>>>>>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>>>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>>>>>> "I'm available at these other addresses too, but not."
>>>>>>> 
>>>>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>>>>>> connection?
>>>>>>> I don't remember ever seeing both types of address in a message,
>>>>>>> but may not have looked.
>>>>>> 
>>>>>> That's an interesting question.  Do the RFCs say anything?  I would
>>>>>> assume it was ok unless ipv6only was set.
>>>>>> 
>>>>>>> 
>>>>>>> I also wonder whether the connection should be dropped for an error
>>>>>>> response on a path that has never been validated.
>>>>>> 
>>>>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>>>>>> is up?  That's kind of the whole point of multihoming.
>>>>> 
>>>>> Michael explained it on the other email. What he described is what I
>>>>> observed in my tests.
>>>>> 
>>>>>> 
>>>>>>> 
>>>>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>>>>>> 
>>>>>> I don't think so.
>>>>>> 
>>>>>>> The IP addresses a server needs to bind to depend on where the
>>>>>>> incoming connection will come from.
>>>>>>> A local connection may be able to use a 192.168.x.x address
>>>>>>> but a remote connection must not - as it may be defined locally
>>>>>>> at the remote system.
>>>>>>> But both connections can come into the public (routable) address.
>>>>>>> We have to tell customers to explicitly configure the local IP
>>>>>>> addresses - which means the application has to know what they are.
>>>>>>> Fortunately these apps are pretty static - usually M3UA.
>>>>>> 
>>>>>> Umm, no,  If you have a private address, it better be behind a firewall,
>>>>>> and the firewall should handle rewriting the packet to fix the addresses.
>>>>>> 
>>>>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>>>>>> the code for this.  But that's how it *should* work.
>>>>> 
>>>>> Right, we don't support SCTP aware NAT [1].
>>>>> 
>>>>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
>>>> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
>>> 
>>> Thanks!
>>> 
>>>> 
>>>> Another possibility for NAT traversal is UDP encapsulation...
>>> 
>>> Also not supported.. :-]
>> But maybe someone wants to implement it. It is supported by FreeBSD, if you
>> need a peer for testing. Or the userland stack usrsctp supports it. Then you
>> do not need root privileges to run it.
> You mean SCTP_REMOTE_UDP_ENCAPS_PORT sockopt, right?
> We have this in our to-do list. I mixed rfc6951 with the userland one.
> Will prioritize this feature. Thanks.
Great to hear. When implementing RFC 6951 support, please take
https://tools.ietf.org/html/draft-tuexen-tsvwg-sctp-udp-encaps-cons-02
into account. It is still valid and will be pushed further after RFC 4960bis
is done.

Best regards
Michael
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Best regards,
>>> Marcelo
>>> 
>>>> 
>>>> Best regards
>>>> Michael
>>>>> 
>>>>> Marcelo
>>>>> 
>>>>>> 
>>>>>> -corey
>>>>>> 
>>>>>>> 
>>>>>>>  David
>>>>>>> 
>>>>>>> -
>>>>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>>>>>> Registration No: 1397386 (Wales)
>>>>>>> 
>>>> 
>> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-24  9:18                         ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-24  9:18 UTC (permalink / raw)
  To: Xin Long
  Cc: Marcelo Ricardo Leitner, Corey Minyard, David Laight,
	Vlad Yasevich, Neil Horman, linux-sctp, LKML

> On 24. Jun 2020, at 09:25, Xin Long <lucien.xin@gmail.com> wrote:
> 
> On Wed, Jun 24, 2020 at 5:48 AM Michael Tuexen
> <michael.tuexen@lurchi.franken.de> wrote:
>> 
>>> On 23. Jun 2020, at 23:31, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>> 
>>> On Tue, Jun 23, 2020 at 11:24:59PM +0200, Michael Tuexen wrote:
>>>>> On 23. Jun 2020, at 23:21, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
>>>>> 
>>>>> On Tue, Jun 23, 2020 at 11:17:56AM -0500, Corey Minyard wrote:
>>>>>> On Tue, Jun 23, 2020 at 01:17:28PM +0000, David Laight wrote:
>>>>>>> From: Marcelo Ricardo Leitner
>>>>>>>> Sent: 22 June 2020 19:33
>>>>>>>> On Mon, Jun 22, 2020 at 08:01:24PM +0200, Michael Tuexen wrote:
>>>>>>>>>> On 22. Jun 2020, at 18:57, Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> On Mon, Jun 22, 2020 at 08:01:23PM +0800, Xin Long wrote:
>>>>>>>>>>> On Sun, Jun 21, 2020 at 11:56 PM Corey Minyard <minyard@acm.org> wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>> I've stumbled upon a strange problem with SCTP and IPv6.  If I create an
>>>>>>>>>>>> sctp listening socket on :: and set the IPV6_V6ONLY socket option on it,
>>>>>>>>>>>> then I make a connection to it using ::1, the connection will drop after
>>>>>>>>>>>> 2.5 seconds with an ECONNRESET error.
>>>>>>>>>>>> 
>>>>>>>>>>>> It only happens on SCTP, it doesn't have the issue if you connect to a
>>>>>>>>>>>> full IPv6 address instead of ::1, and it doesn't happen if you don't
>>>>>>>>>>>> set IPV6_V6ONLY.  I have verified current end of tree kernel.org.
>>>>>>>>>>>> I tried on an ARM system and x86_64.
>>>>>>>>>>>> 
>>>>>>>>>>>> I haven't dug into the kernel to see if I could find anything yet, but I
>>>>>>>>>>>> thought I would go ahead and report it.  I am attaching a reproducer.
>>>>>>>>>>>> Basically, compile the following code:
>>>>>>>>>>> The code only set IPV6_V6ONLY on server side, so the client side will
>>>>>>>>>>> still bind all the local ipv4 addresses (as you didn't call bind() to
>>>>>>>>>>> bind any specific addresses ). Then after the connection is created,
>>>>>>>>>>> the client will send HB on the v4 paths to the server. The server
>>>>>>>>>>> will abort the connection, as it can't support v4.
>>>>>>>>>>> 
>>>>>>>>>>> So you can work around it by either:
>>>>>>>>>>> 
>>>>>>>>>>> - set IPV6_V6ONLY on client side.
>>>>>>>>>>> 
>>>>>>>>>>> or
>>>>>>>>>>> 
>>>>>>>>>>> - bind to the specific v6 addresses on the client side.
>>>>>>>>>>> 
>>>>>>>>>>> I don't see RFC said something about this.
>>>>>>>>>>> So it may not be a good idea to change the current behaviour
>>>>>>>>>>> to not establish the connection in this case, which may cause regression.
>>>>>>>>>> 
>>>>>>>>>> Ok, I understand this.  It's a little strange, but I see why it works
>>>>>>>>>> this way.
>>>>>>>>> I don't. I would expect it to work as I described in my email.
>>>>>>>>> Could someone explain me how and why it is behaving different from
>>>>>>>>> my expectation?
>>>>>>>> 
>>>>>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>>>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>>>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>>>>>> "I'm available at these other addresses too, but not."
>>>>>>> 
>>>>>>> Does it even make sense to mix IPv4 and IPv6 addresses on the same
>>>>>>> connection?
>>>>>>> I don't remember ever seeing both types of address in a message,
>>>>>>> but may not have looked.
>>>>>> 
>>>>>> That's an interesting question.  Do the RFCs say anything?  I would
>>>>>> assume it was ok unless ipv6only was set.
>>>>>> 
>>>>>>> 
>>>>>>> I also wonder whether the connection should be dropped for an error
>>>>>>> response on a path that has never been validated.
>>>>>> 
>>>>>> That actually bothered me a bit more.  Shouldn't it stay up if any path
>>>>>> is up?  That's kind of the whole point of multihoming.
>>>>> 
>>>>> Michael explained it on the other email. What he described is what I
>>>>> observed in my tests.
>>>>> 
>>>>>> 
>>>>>>> 
>>>>>>> OTOH the whole 'multi-homing' part of SCTP sucks.
>>>>>> 
>>>>>> I don't think so.
>>>>>> 
>>>>>>> The IP addresses a server needs to bind to depend on where the
>>>>>>> incoming connection will come from.
>>>>>>> A local connection may be able to use a 192.168.x.x address
>>>>>>> but a remote connection must not - as it may be defined locally
>>>>>>> at the remote system.
>>>>>>> But both connections can come into the public (routable) address.
>>>>>>> We have to tell customers to explicitly configure the local IP
>>>>>>> addresses - which means the application has to know what they are.
>>>>>>> Fortunately these apps are pretty static - usually M3UA.
>>>>>> 
>>>>>> Umm, no,  If you have a private address, it better be behind a firewall,
>>>>>> and the firewall should handle rewriting the packet to fix the addresses.
>>>>>> 
>>>>>> It doesn't appear that Linux netfilter does this.  There is a TODO in
>>>>>> the code for this.  But that's how it *should* work.
>>>>> 
>>>>> Right, we don't support SCTP aware NAT [1].
>>>>> 
>>>>> 1.https://tools.ietf.org/html/draft-stewart-behave-sctpnat-04
>>>> The current version is: https://tools.ietf.org/html/draft-ietf-tsvwg-natsupp-16
>>> 
>>> Thanks!
>>> 
>>>> 
>>>> Another possibility for NAT traversal is UDP encapsulation...
>>> 
>>> Also not supported.. :-]
>> But maybe someone wants to implement it. It is supported by FreeBSD, if you
>> need a peer for testing. Or the userland stack usrsctp supports it. Then you
>> do not need root privileges to run it.
> You mean SCTP_REMOTE_UDP_ENCAPS_PORT sockopt, right?
> We have this in our to-do list. I mixed rfc6951 with the userland one.
> Will prioritize this feature. Thanks.
Great to hear. When implementing RFC 6951 support, please take
https://tools.ietf.org/html/draft-tuexen-tsvwg-sctp-udp-encaps-cons-02
into account. It is still valid and will be pushed further after RFC 4960bis
is done.

Best regards
Michael
> 
>> 
>> Best regards
>> Michael
>>> 
>>> Best regards,
>>> Marcelo
>>> 
>>>> 
>>>> Best regards
>>>> Michael
>>>>> 
>>>>> Marcelo
>>>>> 
>>>>>> 
>>>>>> -corey
>>>>>> 
>>>>>>> 
>>>>>>>  David
>>>>>>> 
>>>>>>> -
>>>>>>> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
>>>>>>> Registration No: 1397386 (Wales)
>>>>>>> 
>>>> 
>> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
  2020-06-23 16:04             ` minyard
@ 2020-06-24 20:31               ` Marcelo Ricardo Leitner
  -1 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-24 20:31 UTC (permalink / raw)
  To: minyard
  Cc: Xin Long, Michael Tuexen, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

On Tue, Jun 23, 2020 at 11:04:17AM -0500, minyard@acm.org wrote:
> From: Corey Minyard <cminyard@mvista.com>
> 
> If a socket was set ipv6only, it would still send IPv4 addresses in the
> init and init ack packets.  So don't add IPv4 addresses to ipv6only
> sockets.
> 
> Based on a patch by Xin Long <lucien.xin@gmail.com>
> 
> Signed-off-by: Corey Minyard <cminyard@mvista.com>
> ---
> I have tested this and it seem to fix the issue.  However, I'm wondering
> if it might be better to fix it where the addresses are put into the
> association as opposed to where they are put into the message.

Yes, it is. It even highlights why this issue was there in the first
place. Sending a patch right after this email.

  Marcelo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
@ 2020-06-24 20:31               ` Marcelo Ricardo Leitner
  0 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-24 20:31 UTC (permalink / raw)
  To: minyard
  Cc: Xin Long, Michael Tuexen, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

On Tue, Jun 23, 2020 at 11:04:17AM -0500, minyard@acm.org wrote:
> From: Corey Minyard <cminyard@mvista.com>
> 
> If a socket was set ipv6only, it would still send IPv4 addresses in the
> init and init ack packets.  So don't add IPv4 addresses to ipv6only
> sockets.
> 
> Based on a patch by Xin Long <lucien.xin@gmail.com>
> 
> Signed-off-by: Corey Minyard <cminyard@mvista.com>
> ---
> I have tested this and it seem to fix the issue.  However, I'm wondering
> if it might be better to fix it where the addresses are put into the
> association as opposed to where they are put into the message.

Yes, it is. It even highlights why this issue was there in the first
place. Sending a patch right after this email.

  Marcelo

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
  2020-06-23 16:04             ` minyard
@ 2020-06-24 20:34               ` Marcelo Ricardo Leitner
  -1 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-24 20:34 UTC (permalink / raw)
  To: netdev
  Cc: Xin Long, Michael Tuexen, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

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: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
 include/net/sctp/constants.h | 8 +++++---
 net/sctp/associola.c         | 5 ++++-
 net/sctp/bind_addr.c         | 1 +
 net/sctp/protocol.c          | 3 ++-
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index 15b4d9aec7ff278e67a7183f10c14be237227d6b..122d9e2d8dfde33b787d575fc42d454732550698 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -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. */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 72315137d7e7f20d5182291ef4b01102f030078b..8d735461fa196567ab19c583703aad098ef8e240 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -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)
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 53bc61537f44f4e766c417fcef72234df52ecd04..701c5a4e441d9c248df9472f22db5b78987f9e44 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -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) &&
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 092d1afdee0d23cd974210839310fbf406dd443f..cde29f3c7fb3c40ee117636fa3b4b7f0a03e4fba 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -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) ||
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
@ 2020-06-24 20:34               ` Marcelo Ricardo Leitner
  0 siblings, 0 replies; 55+ messages in thread
From: Marcelo Ricardo Leitner @ 2020-06-24 20:34 UTC (permalink / raw)
  To: netdev
  Cc: Xin Long, Michael Tuexen, Yasevich, Neil Horman, linux-sctp,
	linux-kernel, Corey Minyard

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: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
 include/net/sctp/constants.h | 8 +++++---
 net/sctp/associola.c         | 5 ++++-
 net/sctp/bind_addr.c         | 1 +
 net/sctp/protocol.c          | 3 ++-
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index 15b4d9aec7ff278e67a7183f10c14be237227d6b..122d9e2d8dfde33b787d575fc42d454732550698 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -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. */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 72315137d7e7f20d5182291ef4b01102f030078b..8d735461fa196567ab19c583703aad098ef8e240 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -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)
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 53bc61537f44f4e766c417fcef72234df52ecd04..701c5a4e441d9c248df9472f22db5b78987f9e44 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -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) &&
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 092d1afdee0d23cd974210839310fbf406dd443f..cde29f3c7fb3c40ee117636fa3b4b7f0a03e4fba 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -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) ||
-- 
2.25.4

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
  2020-06-24 20:34               ` Marcelo Ricardo Leitner
@ 2020-06-24 20:53                 ` Corey Minyard
  -1 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-24 20:53 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: netdev, Xin Long, Michael Tuexen, Yasevich, Neil Horman,
	linux-sctp, linux-kernel

On Wed, Jun 24, 2020 at 05:34:18PM -0300, Marcelo Ricardo Leitner wrote:
> 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 the issue for me.

Tested-by: Corey Minyard <cminyard@mvista.com>

Thanks a bunch.

-corey

> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Corey Minyard <cminyard@mvista.com>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
>  include/net/sctp/constants.h | 8 +++++---
>  net/sctp/associola.c         | 5 ++++-
>  net/sctp/bind_addr.c         | 1 +
>  net/sctp/protocol.c          | 3 ++-
>  4 files changed, 12 insertions(+), 5 deletions(-)
> 
> diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
> index 15b4d9aec7ff278e67a7183f10c14be237227d6b..122d9e2d8dfde33b787d575fc42d454732550698 100644
> --- a/include/net/sctp/constants.h
> +++ b/include/net/sctp/constants.h
> @@ -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. */
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 72315137d7e7f20d5182291ef4b01102f030078b..8d735461fa196567ab19c583703aad098ef8e240 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -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)
> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> index 53bc61537f44f4e766c417fcef72234df52ecd04..701c5a4e441d9c248df9472f22db5b78987f9e44 100644
> --- a/net/sctp/bind_addr.c
> +++ b/net/sctp/bind_addr.c
> @@ -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) &&
> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> index 092d1afdee0d23cd974210839310fbf406dd443f..cde29f3c7fb3c40ee117636fa3b4b7f0a03e4fba 100644
> --- a/net/sctp/protocol.c
> +++ b/net/sctp/protocol.c
> @@ -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) ||
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
@ 2020-06-24 20:53                 ` Corey Minyard
  0 siblings, 0 replies; 55+ messages in thread
From: Corey Minyard @ 2020-06-24 20:53 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner
  Cc: netdev, Xin Long, Michael Tuexen, Yasevich, Neil Horman,
	linux-sctp, linux-kernel

On Wed, Jun 24, 2020 at 05:34:18PM -0300, Marcelo Ricardo Leitner wrote:
> 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 the issue for me.

Tested-by: Corey Minyard <cminyard@mvista.com>

Thanks a bunch.

-corey

> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Corey Minyard <cminyard@mvista.com>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
>  include/net/sctp/constants.h | 8 +++++---
>  net/sctp/associola.c         | 5 ++++-
>  net/sctp/bind_addr.c         | 1 +
>  net/sctp/protocol.c          | 3 ++-
>  4 files changed, 12 insertions(+), 5 deletions(-)
> 
> diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
> index 15b4d9aec7ff278e67a7183f10c14be237227d6b..122d9e2d8dfde33b787d575fc42d454732550698 100644
> --- a/include/net/sctp/constants.h
> +++ b/include/net/sctp/constants.h
> @@ -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. */
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index 72315137d7e7f20d5182291ef4b01102f030078b..8d735461fa196567ab19c583703aad098ef8e240 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -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)
> diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> index 53bc61537f44f4e766c417fcef72234df52ecd04..701c5a4e441d9c248df9472f22db5b78987f9e44 100644
> --- a/net/sctp/bind_addr.c
> +++ b/net/sctp/bind_addr.c
> @@ -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) &&
> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> index 092d1afdee0d23cd974210839310fbf406dd443f..cde29f3c7fb3c40ee117636fa3b4b7f0a03e4fba 100644
> --- a/net/sctp/protocol.c
> +++ b/net/sctp/protocol.c
> @@ -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) ||
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
  2020-06-24 20:34               ` Marcelo Ricardo Leitner
@ 2020-06-25 23:12                 ` David Miller
  -1 siblings, 0 replies; 55+ messages in thread
From: David Miller @ 2020-06-25 23:12 UTC (permalink / raw)
  To: marcelo.leitner
  Cc: netdev, lucien.xin, Michael.Tuexen, vyasevich, nhorman,
	linux-sctp, linux-kernel, cminyard

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: Wed, 24 Jun 2020 17:34:18 -0300

> 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: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Corey Minyard <cminyard@mvista.com>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>

Applied and queued up for -stable, thank you.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH net] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
@ 2020-06-25 23:12                 ` David Miller
  0 siblings, 0 replies; 55+ messages in thread
From: David Miller @ 2020-06-25 23:12 UTC (permalink / raw)
  To: marcelo.leitner
  Cc: netdev, lucien.xin, Michael.Tuexen, vyasevich, nhorman,
	linux-sctp, linux-kernel, cminyard

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: Wed, 24 Jun 2020 17:34:18 -0300

> 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: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Corey Minyard <cminyard@mvista.com>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>

Applied and queued up for -stable, thank you.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* RE: Strange problem with SCTP+IPv6
  2020-06-23 10:13             ` Xin Long
@ 2020-06-26 16:13               ` David Laight
  -1 siblings, 0 replies; 55+ messages in thread
From: David Laight @ 2020-06-26 16:13 UTC (permalink / raw)
  To: 'Xin Long', Michael Tuexen
  Cc: Marcelo Ricardo Leitner, minyard, Vlad Yasevich, Neil Horman,
	linux-sctp, LKML

From: Xin Long
> Sent: 23 June 2020 11:14
> > > It looks like a bug to me. Testing with this test app here, I can see
> > > the INIT_ACK being sent with a bunch of ipv4 addresses in it and
> > > that's unexpected for a v6only socket. As is, it's the server saying
> > > "I'm available at these other addresses too, but not."
> > I agree.
> Then we need a fix in sctp_bind_addrs_to_raw():
> 
> @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
> struct sctp_bind_addr *bp,
>         addrparms = retval;
> 
>         list_for_each_entry(addr, &bp->address_list, list) {
> +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
> +                   (AF_INET == addr->a.sa.sa_family))
> +                       continue;
>                 af = sctp_get_af_specific(addr->a.v4.sin_family);
>                 len = af->to_addr_param(&addr->a, &rawaddr);
>                 memcpy(addrparms.v, &rawaddr, len);

Thought.

Does it make any sense to offer addresses in the INIT_ACK that don't
have routes to those proposed in the received INIT?

'routes' probably isn't exactly the right word.
You probably only want the local address that will be used
as the source address for the probes.
Or, at least, sources addresses that could be used for the probes.

So if the INIT only contains IPv6 addresses should the INIT_ACK
ever contain IPv4 ones.

	David.

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* RE: Strange problem with SCTP+IPv6
@ 2020-06-26 16:13               ` David Laight
  0 siblings, 0 replies; 55+ messages in thread
From: David Laight @ 2020-06-26 16:13 UTC (permalink / raw)
  To: 'Xin Long', Michael Tuexen
  Cc: Marcelo Ricardo Leitner, minyard, Vlad Yasevich, Neil Horman,
	linux-sctp, LKML

RnJvbTogWGluIExvbmcNCj4gU2VudDogMjMgSnVuZSAyMDIwIDExOjE0DQo+ID4gPiBJdCBsb29r
cyBsaWtlIGEgYnVnIHRvIG1lLiBUZXN0aW5nIHdpdGggdGhpcyB0ZXN0IGFwcCBoZXJlLCBJIGNh
biBzZWUNCj4gPiA+IHRoZSBJTklUX0FDSyBiZWluZyBzZW50IHdpdGggYSBidW5jaCBvZiBpcHY0
IGFkZHJlc3NlcyBpbiBpdCBhbmQNCj4gPiA+IHRoYXQncyB1bmV4cGVjdGVkIGZvciBhIHY2b25s
eSBzb2NrZXQuIEFzIGlzLCBpdCdzIHRoZSBzZXJ2ZXIgc2F5aW5nDQo+ID4gPiAiSSdtIGF2YWls
YWJsZSBhdCB0aGVzZSBvdGhlciBhZGRyZXNzZXMgdG9vLCBidXQgbm90LiINCj4gPiBJIGFncmVl
Lg0KPiBUaGVuIHdlIG5lZWQgYSBmaXggaW4gc2N0cF9iaW5kX2FkZHJzX3RvX3JhdygpOg0KPiAN
Cj4gQEAgLTIzOCw2ICsyNDAsOSBAQCB1bmlvbiBzY3RwX3BhcmFtcyBzY3RwX2JpbmRfYWRkcnNf
dG9fcmF3KGNvbnN0DQo+IHN0cnVjdCBzY3RwX2JpbmRfYWRkciAqYnAsDQo+ICAgICAgICAgYWRk
cnBhcm1zID0gcmV0dmFsOw0KPiANCj4gICAgICAgICBsaXN0X2Zvcl9lYWNoX2VudHJ5KGFkZHIs
ICZicC0+YWRkcmVzc19saXN0LCBsaXN0KSB7DQo+ICsgICAgICAgICAgICAgICBpZiAoKFBGX0lO
RVQ2ID09IHNrLT5za19mYW1pbHkpICYmIGluZXRfdjZfaXB2Nm9ubHkoc2spICYmDQo+ICsgICAg
ICAgICAgICAgICAgICAgKEFGX0lORVQgPT0gYWRkci0+YS5zYS5zYV9mYW1pbHkpKQ0KPiArICAg
ICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gICAgICAgICAgICAgICAgIGFmID0gc2N0
cF9nZXRfYWZfc3BlY2lmaWMoYWRkci0+YS52NC5zaW5fZmFtaWx5KTsNCj4gICAgICAgICAgICAg
ICAgIGxlbiA9IGFmLT50b19hZGRyX3BhcmFtKCZhZGRyLT5hLCAmcmF3YWRkcik7DQo+ICAgICAg
ICAgICAgICAgICBtZW1jcHkoYWRkcnBhcm1zLnYsICZyYXdhZGRyLCBsZW4pOw0KDQpUaG91Z2h0
Lg0KDQpEb2VzIGl0IG1ha2UgYW55IHNlbnNlIHRvIG9mZmVyIGFkZHJlc3NlcyBpbiB0aGUgSU5J
VF9BQ0sgdGhhdCBkb24ndA0KaGF2ZSByb3V0ZXMgdG8gdGhvc2UgcHJvcG9zZWQgaW4gdGhlIHJl
Y2VpdmVkIElOSVQ/DQoNCidyb3V0ZXMnIHByb2JhYmx5IGlzbid0IGV4YWN0bHkgdGhlIHJpZ2h0
IHdvcmQuDQpZb3UgcHJvYmFibHkgb25seSB3YW50IHRoZSBsb2NhbCBhZGRyZXNzIHRoYXQgd2ls
bCBiZSB1c2VkDQphcyB0aGUgc291cmNlIGFkZHJlc3MgZm9yIHRoZSBwcm9iZXMuDQpPciwgYXQg
bGVhc3QsIHNvdXJjZXMgYWRkcmVzc2VzIHRoYXQgY291bGQgYmUgdXNlZCBmb3IgdGhlIHByb2Jl
cy4NCg0KU28gaWYgdGhlIElOSVQgb25seSBjb250YWlucyBJUHY2IGFkZHJlc3NlcyBzaG91bGQg
dGhlIElOSVRfQUNLDQpldmVyIGNvbnRhaW4gSVB2NCBvbmVzLg0KDQoJRGF2aWQuDQoNCi0NClJl
Z2lzdGVyZWQgQWRkcmVzcyBMYWtlc2lkZSwgQnJhbWxleSBSb2FkLCBNb3VudCBGYXJtLCBNaWx0
b24gS2V5bmVzLCBNSzEgMVBULCBVSw0KUmVnaXN0cmF0aW9uIE5vOiAxMzk3Mzg2IChXYWxlcykN
Cg=

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
  2020-06-26 16:13               ` David Laight
@ 2020-06-26 16:27                 ` Michael Tuexen
  -1 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-26 16:27 UTC (permalink / raw)
  To: David Laight
  Cc: Xin Long, Marcelo Ricardo Leitner, minyard, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 26. Jun 2020, at 18:13, David Laight <David.Laight@ACULAB.COM> wrote:
> 
> From: Xin Long
>> Sent: 23 June 2020 11:14
>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>> "I'm available at these other addresses too, but not."
>>> I agree.
>> Then we need a fix in sctp_bind_addrs_to_raw():
>> 
>> @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
>> struct sctp_bind_addr *bp,
>>        addrparms = retval;
>> 
>>        list_for_each_entry(addr, &bp->address_list, list) {
>> +               if ((PF_INET6 == sk->sk_family) && inet_v6_ipv6only(sk) &&
>> +                   (AF_INET == addr->a.sa.sa_family))
>> +                       continue;
>>                af = sctp_get_af_specific(addr->a.v4.sin_family);
>>                len = af->to_addr_param(&addr->a, &rawaddr);
>>                memcpy(addrparms.v, &rawaddr, len);
> 
> Thought.
> 
> Does it make any sense to offer addresses in the INIT_ACK that don't
> have routes to those proposed in the received INIT?
> 
> 'routes' probably isn't exactly the right word.
> You probably only want the local address that will be used
> as the source address for the probes.
> Or, at least, sources addresses that could be used for the probes.
> 
> So if the INIT only contains IPv6 addresses should the INIT_ACK
> ever contain IPv4 ones.
The client (if it not using an IPv6 socket having IPv6 only enabled) could
add an IPv4 address during the lifetime of the association by using the
address reconfiguration extension.

What could be done is to not send IPv4 addresses if the INIT contains
a Supported Address Types parameter indicating IPv6, but not IPv4 support.
As a client you might want to send this parameter, when the IPv6 socket has
enabled the IPV6_ONLY socket option.
Also if the client uses an IPv4 socket, it can indicate in the Supported
Address Parameter that it only support IPv4, and the server does not need
to list IPv6 addresses.

Best regards
Michael
> 
> 	David.
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: Strange problem with SCTP+IPv6
@ 2020-06-26 16:27                 ` Michael Tuexen
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Tuexen @ 2020-06-26 16:27 UTC (permalink / raw)
  To: David Laight
  Cc: Xin Long, Marcelo Ricardo Leitner, minyard, Vlad Yasevich,
	Neil Horman, linux-sctp, LKML

> On 26. Jun 2020, at 18:13, David Laight <David.Laight@ACULAB.COM> wrote:
> 
> From: Xin Long
>> Sent: 23 June 2020 11:14
>>>> It looks like a bug to me. Testing with this test app here, I can see
>>>> the INIT_ACK being sent with a bunch of ipv4 addresses in it and
>>>> that's unexpected for a v6only socket. As is, it's the server saying
>>>> "I'm available at these other addresses too, but not."
>>> I agree.
>> Then we need a fix in sctp_bind_addrs_to_raw():
>> 
>> @@ -238,6 +240,9 @@ union sctp_params sctp_bind_addrs_to_raw(const
>> struct sctp_bind_addr *bp,
>>        addrparms = retval;
>> 
>>        list_for_each_entry(addr, &bp->address_list, list) {
>> +               if ((PF_INET6 = sk->sk_family) && inet_v6_ipv6only(sk) &&
>> +                   (AF_INET = addr->a.sa.sa_family))
>> +                       continue;
>>                af = sctp_get_af_specific(addr->a.v4.sin_family);
>>                len = af->to_addr_param(&addr->a, &rawaddr);
>>                memcpy(addrparms.v, &rawaddr, len);
> 
> Thought.
> 
> Does it make any sense to offer addresses in the INIT_ACK that don't
> have routes to those proposed in the received INIT?
> 
> 'routes' probably isn't exactly the right word.
> You probably only want the local address that will be used
> as the source address for the probes.
> Or, at least, sources addresses that could be used for the probes.
> 
> So if the INIT only contains IPv6 addresses should the INIT_ACK
> ever contain IPv4 ones.
The client (if it not using an IPv6 socket having IPv6 only enabled) could
add an IPv4 address during the lifetime of the association by using the
address reconfiguration extension.

What could be done is to not send IPv4 addresses if the INIT contains
a Supported Address Types parameter indicating IPv6, but not IPv4 support.
As a client you might want to send this parameter, when the IPv6 socket has
enabled the IPV6_ONLY socket option.
Also if the client uses an IPv4 socket, it can indicate in the Supported
Address Parameter that it only support IPv4, and the server does not need
to list IPv6 addresses.

Best regards
Michael
> 
> 	David.
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2020-06-26 16:27 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-21 15:56 Strange problem with SCTP+IPv6 Corey Minyard
2020-06-21 15:56 ` Corey Minyard
2020-06-22 11:52 ` Xin Long
2020-06-22 12:01   ` Xin Long
2020-06-22 12:32   ` Michael Tuexen
2020-06-22 12:32     ` Michael Tuexen
2020-06-22 16:57   ` Corey Minyard
2020-06-22 16:57     ` Corey Minyard
2020-06-22 18:01     ` Michael Tuexen
2020-06-22 18:01       ` Michael Tuexen
2020-06-22 18:32       ` Marcelo Ricardo Leitner
2020-06-22 18:32         ` Marcelo Ricardo Leitner
2020-06-22 18:34         ` Michael Tuexen
2020-06-22 18:34           ` Michael Tuexen
2020-06-23 10:13           ` Xin Long
2020-06-23 10:13             ` Xin Long
2020-06-23 13:29             ` Corey Minyard
2020-06-23 13:29               ` Corey Minyard
2020-06-23 15:40               ` Xin Long
2020-06-23 15:40                 ` Xin Long
2020-06-23 16:00                 ` Corey Minyard
2020-06-23 16:00                   ` Corey Minyard
2020-06-24  6:58                   ` Xin Long
2020-06-24  6:58                     ` Xin Long
2020-06-26 16:13             ` David Laight
2020-06-26 16:13               ` David Laight
2020-06-26 16:27               ` Michael Tuexen
2020-06-26 16:27                 ` Michael Tuexen
2020-06-23 13:17         ` David Laight
2020-06-23 16:04           ` [PATCH] sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket minyard
2020-06-23 16:04             ` minyard
2020-06-24 20:31             ` Marcelo Ricardo Leitner
2020-06-24 20:31               ` Marcelo Ricardo Leitner
2020-06-24 20:34             ` [PATCH net] " Marcelo Ricardo Leitner
2020-06-24 20:34               ` Marcelo Ricardo Leitner
2020-06-24 20:53               ` Corey Minyard
2020-06-24 20:53                 ` Corey Minyard
2020-06-25 23:12               ` David Miller
2020-06-25 23:12                 ` David Miller
2020-06-23 16:17           ` Strange problem with SCTP+IPv6 Corey Minyard
2020-06-23 16:17             ` Corey Minyard
2020-06-23 21:21             ` 'Marcelo Ricardo Leitner'
2020-06-23 21:21               ` 'Marcelo Ricardo Leitner'
2020-06-23 21:24               ` Michael Tuexen
2020-06-23 21:24                 ` Michael Tuexen
2020-06-23 21:31                 ` Marcelo Ricardo Leitner
2020-06-23 21:31                   ` Marcelo Ricardo Leitner
2020-06-23 21:48                   ` Michael Tuexen
2020-06-23 21:48                     ` Michael Tuexen
2020-06-24  7:25                     ` Xin Long
2020-06-24  7:25                       ` Xin Long
2020-06-24  9:18                       ` Michael Tuexen
2020-06-24  9:18                         ` Michael Tuexen
2020-06-23 17:09           ` Michael Tuexen
2020-06-23 17:09             ` Michael Tuexen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.