Date: Wed, 24 Nov 2021 04:53:45 +0200 From: Konstantin Belousov <kostikbel@gmail.com> To: jschauma@netmeister.org Cc: freebsd-net@freebsd.org Subject: Re: bind() to ::1 fails with EADDRNOTAVAIL / clang vs gcc Message-ID: <YZ2pOWNVMp3dCs6p@kib.kiev.ua> In-Reply-To: <20211124020839.GZ11277@netmeister.org> References: <20211124020839.GZ11277@netmeister.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Nov 23, 2021 at 09:08:39PM -0500, Jan Schaumann via freebsd-net wrote: > Hello, > > I'm observing the following strange behavior, where > trying to bind(2) a socket on "::1" fails with > EADDRNOTAVAIL, but binding in6addr_any will succeed > (and then yield a bound ::1). What's more, the > behavior is inconsistent depending on the compiler > used. > > Here's my sample program a.c: > > ---- > #include <arpa/inet.h> > #include <sys/socket.h> > > #include <netinet/in.h> > > #include <err.h> > #include <stdlib.h> > > #define PORT 12345 > > int > main(int argc, char **argv) { > int sock; > socklen_t a, b; > struct sockaddr_storage server; > struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&server; > > if ((sock = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { > err(EXIT_FAILURE, "socket"); > /* NOTREACHED */ > } > > if (inet_pton(PF_INET6, "::1", &(sin->sin6_addr)) != 1) { > err(EXIT_FAILURE, "inet_pton"); > /* NOTREACHED */ > } > > sin->sin6_family = PF_INET6; > sin->sin6_port = htons(PORT); > > if (bind(sock, (struct sockaddr *)sin, sizeof(*sin)) != 0) { > err(EXIT_FAILURE, "bind"); > /* NOTREACHED */ > } > > return 0; > } > ---- > > This program succeeds in binding and returns 0, as > expected. However, note the declaration of the unused > socklen_t a and b. If I remove that declaration, the > call to bind(2) will fail: > > $ diff -bu [ab].c > --- a.c 2021-11-23 19:49:05.926884000 +0000 > +++ b.c 2021-11-23 19:48:51.409173000 +0000 > @@ -11,7 +11,6 @@ > int > main(int argc, char **argv) { > int sock; > - socklen_t a, b; > struct sockaddr_storage server; > struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&server; > > $ ./a.out > $ echo $? > 0 > $ cc b.c > $ ./a.out > a.out: bind: Can't assign requested address > $ > > This is on FreeBSD 13.0-RELEASE with FreeBSD clang > version 11.0.1. > > Compiling either with gcc version 10.3.0 fails. > > > So my questions are: > > - Why does _any_ of those fail? > - Why does a.c succeed when compiled with clang, but > b.c does not? Most likely because you did not fully initialized *sin. struct sockaddr_in6 is more complex than just address/port/family. There is also at least scope_id, and something called flow_id. You did not initialized these fields. By adding unused stack variables, you changed the place on stack where sockaddr_in6 structure was laid out, systematically chaning assigned values to these fields. Really it is UB, try to memset(sin, 0, sizeof(*sin)).
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?YZ2pOWNVMp3dCs6p>