curl_addrinfo: support operating systems with only getaddrinfo(3)

The gethostbyname(3) family was removed in POSIX-1.2008 in favor of
getaddrinfo(3) introduced in POSIX-1.2001. Modern POSIX systems such as
Sortix does not have gethostbyname nor the related definitions and
structures.

curl already only uses getaddrinfo(3) if available and thread safe,
although there is mild breakage if the related gethostbyname definitions
are missing.

This change attempts to fix that breakage:

Remove an unnecessary configure error if gethostbyname is missing since
getaddrinfo is enough as a fallback.

Rewrite Curl_ip2addr to not use struct hostent as it no longer is
standardized and create the struct Curl_addrinfo directly.

Only define the Curl_he2ai function on non-getaddrinfo systems where it
is going to be used with struct hoestent.

Revoke the fallback logic for when it's unknown whether getaddrinfo is
thread safe. It doesn't appear to make any sense since h_errno is
unrelated to getaddrinfo. The logic prevents new POSIX.1-2024 systems
from passing the thread safety test since h_errno does not exist anymore
and POSIX already requires getaddrinfo to be thread safe. There's
already a denylist in place for operating systems with known buggy
implementations.

Closes #15475
This commit is contained in:
Jonas 'Sortie' Termansen 2024-11-01 23:53:00 +01:00 committed by Daniel Stenberg
parent 25025419c9
commit 78c3172921
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 53 additions and 110 deletions

View File

@ -1355,10 +1355,6 @@ if test "$HAVE_GETHOSTBYNAME" != "1"; then
) )
fi fi
if test "$HAVE_GETHOSTBYNAME" != "1"; then
AC_MSG_ERROR([couldn't find libraries for gethostbyname()])
fi
CURL_CHECK_LIBS_CONNECT CURL_CHECK_LIBS_CONNECT
CURL_NETWORK_LIBS=$LIBS CURL_NETWORK_LIBS=$LIBS

View File

@ -252,6 +252,7 @@ Curl_getaddrinfo_ex(const char *nodename,
* #define h_addr h_addr_list[0] * #define h_addr h_addr_list[0]
*/ */
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
struct Curl_addrinfo * struct Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port) Curl_he2ai(const struct hostent *he, int port)
{ {
@ -350,19 +351,7 @@ Curl_he2ai(const struct hostent *he, int port)
return firstai; return firstai;
} }
struct namebuff {
struct hostent hostentry;
union {
struct in_addr ina4;
#ifdef USE_IPV6
struct in6_addr ina6;
#endif #endif
} addrentry;
char *h_addr_list[2];
};
/* /*
* Curl_ip2addr() * Curl_ip2addr()
@ -377,71 +366,68 @@ struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
{ {
struct Curl_addrinfo *ai; struct Curl_addrinfo *ai;
#if defined(__VMS) && \
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
#pragma pointer_size save
#pragma pointer_size short
#pragma message disable PTRMISMATCH
#endif
struct hostent *h;
struct namebuff *buf;
char *addrentry;
char *hoststr;
size_t addrsize; size_t addrsize;
size_t namelen;
struct sockaddr_in *addr;
#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
DEBUGASSERT(inaddr && hostname); DEBUGASSERT(inaddr && hostname);
buf = malloc(sizeof(struct namebuff)); namelen = strlen(hostname) + 1;
if(!buf)
if(af == AF_INET)
addrsize = sizeof(struct sockaddr_in);
#ifdef USE_IPV6
else if(af == AF_INET6)
addrsize = sizeof(struct sockaddr_in6);
#endif
else
return NULL; return NULL;
hoststr = strdup(hostname); /* allocate memory to hold the struct, the address and the name */
if(!hoststr) { ai = calloc(1, sizeof(struct Curl_addrinfo) + addrsize + namelen);
free(buf); if(!ai)
return NULL; return NULL;
} /* put the address after the struct */
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
/* then put the name after the address */
ai->ai_canonname = (char *)ai->ai_addr + addrsize;
memcpy(ai->ai_canonname, hostname, namelen);
ai->ai_family = af;
ai->ai_socktype = SOCK_STREAM;
ai->ai_addrlen = (curl_socklen_t)addrsize;
/* leave the rest of the struct filled with zero */
switch(af) { switch(af) {
case AF_INET: case AF_INET:
addrsize = sizeof(struct in_addr); addr = (void *)ai->ai_addr; /* storage area for this info */
addrentry = (void *)&buf->addrentry.ina4;
memcpy(addrentry, inaddr, sizeof(struct in_addr)); memcpy(&addr->sin_addr, inaddr, sizeof(struct in_addr));
#ifdef __MINGW32__
addr->sin_family = (short)af;
#else
addr->sin_family = (CURL_SA_FAMILY_T)af;
#endif
addr->sin_port = htons((unsigned short)port);
break; break;
#ifdef USE_IPV6 #ifdef USE_IPV6
case AF_INET6: case AF_INET6:
addrsize = sizeof(struct in6_addr); addr6 = (void *)ai->ai_addr; /* storage area for this info */
addrentry = (void *)&buf->addrentry.ina6;
memcpy(addrentry, inaddr, sizeof(struct in6_addr)); memcpy(&addr6->sin6_addr, inaddr, sizeof(struct in6_addr));
#ifdef __MINGW32__
addr6->sin6_family = (short)af;
#else
addr6->sin6_family = (CURL_SA_FAMILY_T)af;
#endif
addr6->sin6_port = htons((unsigned short)port);
break; break;
#endif #endif
default:
free(hoststr);
free(buf);
return NULL;
} }
h = &buf->hostentry;
h->h_name = hoststr;
h->h_aliases = NULL;
h->h_addrtype = (short)af;
h->h_length = (short)addrsize;
h->h_addr_list = &buf->h_addr_list[0];
h->h_addr_list[0] = addrentry;
h->h_addr_list[1] = NULL; /* terminate list of entries */
#if defined(__VMS) && \
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
#pragma pointer_size restore
#pragma message enable PTRMISMATCH
#endif
ai = Curl_he2ai(h, port);
free(hoststr);
free(buf);
return ai; return ai;
} }

View File

@ -71,8 +71,10 @@ Curl_getaddrinfo_ex(const char *nodename,
struct Curl_addrinfo **result); struct Curl_addrinfo **result);
#endif #endif
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
struct Curl_addrinfo * struct Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port); Curl_he2ai(const struct hostent *he, int port);
#endif
struct Curl_addrinfo * struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);

View File

@ -126,8 +126,10 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
int res; int res;
#endif #endif
struct Curl_addrinfo *ai = NULL; struct Curl_addrinfo *ai = NULL;
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
struct hostent *h = NULL; struct hostent *h = NULL;
struct hostent *buf = NULL; struct hostent *buf = NULL;
#endif
#if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE) #if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)
struct addrinfo hints; struct addrinfo hints;
@ -288,12 +290,14 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) || #endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
HAVE_GETHOSTBYNAME_R */ HAVE_GETHOSTBYNAME_R */
#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
if(h) { if(h) {
ai = Curl_he2ai(h, port); ai = Curl_he2ai(h, port);
if(buf) /* used a *_r() function */ if(buf) /* used a *_r() function */
free(buf); free(buf);
} }
#endif
return ai; return ai;
} }

View File

@ -1484,52 +1484,7 @@ AC_DEFUN([CURL_CHECK_FUNC_GETADDRINFO], [
tst_tsafe_getaddrinfo="yes" tst_tsafe_getaddrinfo="yes"
fi fi
if test "$tst_tsafe_getaddrinfo" = "unknown"; then if test "$tst_tsafe_getaddrinfo" = "unknown"; then
CURL_CHECK_DEF_CC([h_errno], [ tst_tsafe_getaddrinfo="yes"
$curl_includes_sys_socket
$curl_includes_netdb
], [silent])
if test "$curl_cv_have_def_h_errno" = "yes"; then
tst_h_errno_macro="yes"
else
tst_h_errno_macro="no"
fi
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
$curl_includes_sys_socket
$curl_includes_netdb
]],[[
h_errno = 2;
if(0 != h_errno)
return 1;
]])
],[
tst_h_errno_modifiable_lvalue="yes"
],[
tst_h_errno_modifiable_lvalue="no"
])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
]],[[
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
return 0;
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
return 0;
#else
#error force compilation error
#endif
]])
],[
tst_h_errno_sbs_issue_7="yes"
],[
tst_h_errno_sbs_issue_7="no"
])
if test "$tst_h_errno_macro" = "no" &&
test "$tst_h_errno_modifiable_lvalue" = "no" &&
test "$tst_h_errno_sbs_issue_7" = "no"; then
tst_tsafe_getaddrinfo="no"
else
tst_tsafe_getaddrinfo="yes"
fi
fi fi
AC_MSG_RESULT([$tst_tsafe_getaddrinfo]) AC_MSG_RESULT([$tst_tsafe_getaddrinfo])
if test "$tst_tsafe_getaddrinfo" = "yes"; then if test "$tst_tsafe_getaddrinfo" = "yes"; then