apps: Use the first detected address family if IPv6 is not available

This is a follow up of 15729bef38.  Even
when the host does not support IPv6 at all, BIO_lookup_ex may now
return IN6ADDR_ANY in addition to INADDR_ANY, as the second element of
the ai_next field.

After eee8a40aa5, the do_server function
prefers the IPv6 address and fails on the BIO_socket call.  This adds
a fallback code to retry with the IPv4 address returned as the first
element to avoid the error.

The failure had been partially avoided in the previous code with
AI_ADDRCONFIG, because getaddrinfo returns only IPv4 address if no
IPv6 address is associated with external interface.  However, it would
be still a problem if the external interface has an IPv6 address
assigned, while the loopback interface doesn't.

Signed-off-by: Daiki Ueno <dueno@redhat.com>

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16074)
This commit is contained in:
Daiki Ueno 2021-07-14 11:15:34 +02:00 committed by Tomas Mraz
parent 52f7e44ec8
commit 09c1db3399
1 changed files with 10 additions and 0 deletions

View File

@ -267,6 +267,8 @@ int do_server(int *accept_sock, const char *host, const char *port,
const BIO_ADDRINFO *next;
int sock_family, sock_type, sock_protocol, sock_port;
const BIO_ADDR *sock_address;
int sock_family_fallback = AF_UNSPEC;
const BIO_ADDR *sock_address_fallback = NULL;
int sock_options = BIO_SOCK_REUSEADDR;
int ret = 0;
@ -298,6 +300,10 @@ int do_server(int *accept_sock, const char *host, const char *port,
&& BIO_ADDRINFO_protocol(next) == sock_protocol) {
if (sock_family == AF_INET
&& BIO_ADDRINFO_family(next) == AF_INET6) {
/* In case AF_INET6 is returned but not supported by the
* kernel, retry with the first detected address family */
sock_family_fallback = sock_family;
sock_address_fallback = sock_address;
sock_family = AF_INET6;
sock_address = BIO_ADDRINFO_address(next);
} else if (sock_family == AF_INET6
@ -308,6 +314,10 @@ int do_server(int *accept_sock, const char *host, const char *port,
#endif
asock = BIO_socket(sock_family, sock_type, sock_protocol, 0);
if (asock == INVALID_SOCKET && sock_family_fallback != AF_UNSPEC) {
asock = BIO_socket(sock_family_fallback, sock_type, sock_protocol, 0);
sock_address = sock_address_fallback;
}
if (asock == INVALID_SOCKET
|| !BIO_listen(asock, sock_address, sock_options)) {
BIO_ADDRINFO_free(res);