bind() to ::1 fails with EADDRNOTAVAIL / clang vs gcc
Date: Wed, 24 Nov 2021 02:08:39 UTC
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?
-Jan