From 005addf5515e34486f02a8ec3d1bff6b38550968 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 10:58:27 -0300 Subject: [PATCH 01/17] Convert gethostbyname(l) to use getaddrinfo php_network_getaddresses is our wrapper function around getaddrinfo, the modern replacement for gethostbyname/addr. This converts these userland functions to use the newer API, which does have some benefits... that these functions can't yet take advantage of. Other references to gethostbyname/addr will be removed in future commits, to eventually remove the PHP wrappers in the next ABI break. Note that php_network_getaddresses does its own E_WARNINGs. Note that these functions are documented as only supporting IPv4 addresses; we need to do another BC break to return IPv6 addresses. --- ext/standard/dns.c | 108 ++++++++++-------- .../tests/network/gethostbyname_error003.phpt | 3 +- .../tests/network/gethostbyname_error006.phpt | 3 +- 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/ext/standard/dns.c b/ext/standard/dns.c index 04477129e3599..a0b84afa3029c 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -118,7 +118,6 @@ extern void __res_ndestroy(res_state statp); /* }}} */ static zend_string *php_gethostbyaddr(char *ip); -static zend_string *php_gethostbyname(char *name); #ifdef HAVE_GETHOSTNAME /* {{{ Get the host name of the current machine */ @@ -220,7 +219,8 @@ PHP_FUNCTION(gethostbyname) { char *hostname; size_t hostname_len; - zend_string *ipaddr; + char addr4[INET_ADDRSTRLEN]; + zend_string *ipaddr_zs = NULL; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH(hostname, hostname_len) @@ -232,11 +232,47 @@ PHP_FUNCTION(gethostbyname) RETURN_STRINGL(hostname, hostname_len); } - if (!(ipaddr = php_gethostbyname(hostname))) { + struct sockaddr **addresses = NULL; + zend_string *gai_error = NULL; + int address_count = php_network_getaddresses(hostname, 0, &addresses, &gai_error); + if (gai_error) { + zend_string_release_ex(gai_error, 0); + } + if (address_count == 0) { + /* don't need to docref here, getaddresses E_WARNINGs for us */ + RETURN_STRINGL(hostname, hostname_len); + } + + /* + * Future behaviour change: This function is documented as only returning IPv4 + * addresses. We should change this to return IPv6 addresses as well. + */ + for (struct sockaddr **address_p = addresses; *address_p != NULL; address_p++) { + struct sockaddr *address = *address_p; + + if (address->sa_family != AF_INET) { + continue; + } + + struct sockaddr_in *address4 = (struct sockaddr_in*)address; + const char *ipaddr; + if (!(ipaddr = inet_ntop(AF_INET, &address4->sin_addr, addr4, INET_ADDRSTRLEN))) { + /* unlikely regarding (too) long hostname and protocols but checking still */ + php_error_docref(NULL, E_WARNING, "Host name to ip failed %s", hostname); + continue; + } else { + ipaddr_zs = zend_string_init(ipaddr, strlen(ipaddr), 0); + break; /* we take only first IP for this function */ + } + } + + php_network_freeaddresses(addresses); + + if (ipaddr_zs == NULL) { php_error_docref(NULL, E_WARNING, "Host name to ip failed %s", hostname); RETURN_STRINGL(hostname, hostname_len); } else { - RETURN_STR(ipaddr); + RETURN_STR(ipaddr_zs); } } /* }}} */ @@ -246,9 +282,6 @@ PHP_FUNCTION(gethostbynamel) { char *hostname; size_t hostname_len; - struct hostent *hp; - struct in_addr in; - int i; char addr4[INET_ADDRSTRLEN]; ZEND_PARSE_PARAMETERS_START(1, 1) @@ -261,24 +294,33 @@ PHP_FUNCTION(gethostbynamel) RETURN_FALSE; } - hp = php_network_gethostbyname(hostname); - if (!hp) { + struct sockaddr **addresses = NULL; + zend_string *gai_error = NULL; + int address_count = php_network_getaddresses(hostname, 0, &addresses, &gai_error); + if (gai_error) { + zend_string_release_ex(gai_error, 0); + } + if (address_count == 0) { + /* don't need to docref here, getaddresses E_WARNINGs for us */ RETURN_FALSE; } array_init(return_value); - for (i = 0;; i++) { - /* On macos h_addr_list entries may be misaligned. */ - const char *ipaddr; - struct in_addr *h_addr_entry; /* Don't call this h_addr, it's a macro! */ - memcpy(&h_addr_entry, &hp->h_addr_list[i], sizeof(struct in_addr *)); - if (!h_addr_entry) { - return; + /* + * Future behaviour change: This function is documented as only returning IPv4 + * addresses. We should change this to return IPv6 addresses as well. + */ + for (struct sockaddr **address_p = addresses; *address_p != NULL; address_p++) { + struct sockaddr *address = *address_p; + + if (address->sa_family != AF_INET) { + continue; } - in = *h_addr_entry; - if (!(ipaddr = inet_ntop(AF_INET, &in, addr4, INET_ADDRSTRLEN))) { + struct sockaddr_in *address4 = (struct sockaddr_in*)address; + const char *ipaddr; + if (!(ipaddr = inet_ntop(AF_INET, &address4->sin_addr, addr4, INET_ADDRSTRLEN))) { /* unlikely regarding (too) long hostname and protocols but checking still */ php_error_docref(NULL, E_WARNING, "Host name to ip failed %s", hostname); continue; @@ -286,36 +328,8 @@ PHP_FUNCTION(gethostbynamel) add_next_index_string(return_value, ipaddr); } } -} -/* }}} */ - -/* {{{ php_gethostbyname */ -static zend_string *php_gethostbyname(char *name) -{ - struct hostent *hp; - struct in_addr *h_addr_0; /* Don't call this h_addr, it's a macro! */ - struct in_addr in; - char addr4[INET_ADDRSTRLEN]; - const char *address; - - hp = php_network_gethostbyname(name); - if (!hp) { - return zend_string_init(name, strlen(name), 0); - } - - /* On macos h_addr_list entries may be misaligned. */ - memcpy(&h_addr_0, &hp->h_addr_list[0], sizeof(struct in_addr *)); - if (!h_addr_0) { - return zend_string_init(name, strlen(name), 0); - } - - memcpy(&in.s_addr, h_addr_0, sizeof(in.s_addr)); - - if (!(address = inet_ntop(AF_INET, &in, addr4, INET_ADDRSTRLEN))) { - return NULL; - } - return zend_string_init(address, strlen(address), 0); + php_network_freeaddresses(addresses); } /* }}} */ diff --git a/ext/standard/tests/network/gethostbyname_error003.phpt b/ext/standard/tests/network/gethostbyname_error003.phpt index ebc8a971cb016..47ae902bb4ad2 100644 --- a/ext/standard/tests/network/gethostbyname_error003.phpt +++ b/ext/standard/tests/network/gethostbyname_error003.phpt @@ -6,5 +6,6 @@ gethostbyname() function - basic type return error test ---EXPECT-- +--EXPECTF-- +Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for asdfasdf failed: nodename nor servname provided, or not known in %s on line %d bool(true) diff --git a/ext/standard/tests/network/gethostbyname_error006.phpt b/ext/standard/tests/network/gethostbyname_error006.phpt index 156ba0e623c30..764f3fce5c5d1 100644 --- a/ext/standard/tests/network/gethostbyname_error006.phpt +++ b/ext/standard/tests/network/gethostbyname_error006.phpt @@ -6,5 +6,6 @@ gethostbyname() function - basic invalid parameter test ---EXPECT-- +--EXPECTF-- +Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for .toto.toto.toto failed: nodename nor servname provided, or not known in %s on line %d string(15) ".toto.toto.toto" From d5b3cfe45f835cd189422d7e662d61d3f0b76941 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 11:25:58 -0300 Subject: [PATCH 02/17] Add php_network_getaddresses_ex Allows controlling the address family and flags to use. --- main/network.c | 16 +++++++++++++--- main/php_network.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/main/network.c b/main/network.c index bf34043362dab..49657a1397dab 100644 --- a/main/network.c +++ b/main/network.c @@ -143,10 +143,10 @@ PHPAPI void php_network_freeaddresses(struct sockaddr **sal) } /* }}} */ -/* {{{ php_network_getaddresses +/* {{{ php_network_getaddresses_ex * Returns number of addresses, 0 for none/error */ -PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string) +PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string) { struct sockaddr **sap; int n; @@ -168,6 +168,7 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka hints.ai_family = AF_INET; /* default to regular inet (see below) */ hints.ai_socktype = socktype; + hints.ai_flags = ai_flags; # ifdef HAVE_IPV6 /* probe for a working IPv6 stack; even if detected as having v6 at compile @@ -187,7 +188,7 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka closesocket(s); } } - hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC; + hints.ai_family = ipv6_borked ? AF_INET : family; # endif if ((n = getaddrinfo(host, NULL, &hints, &res))) { @@ -269,6 +270,15 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka } /* }}} */ +/* {{{ php_network_getaddresses + * Returns number of addresses, 0 for none/error + */ +PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string) +{ + return php_network_getaddresses_ex(host, socktype, AF_UNSPEC, 0, sal, error_string); +} +/* }}} */ + #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif diff --git a/main/php_network.h b/main/php_network.h index 06da95dd68ce6..d71a878d220d6 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -261,6 +261,7 @@ typedef struct { BEGIN_EXTERN_C() PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string); +PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string); PHPAPI void php_network_freeaddresses(struct sockaddr **sal); PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, From b7b502848047dce1ed2a61e922bf1ae6e71678bc Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 11:42:13 -0300 Subject: [PATCH 03/17] Convert sockaddr_conv.c to use getaddrinfo for v4 Not ideal right now; it should really be using the PHP wrapper function, and have bool conversion. But it does get rid of a use of gethostbyname. --- ext/sockets/sockaddr_conv.c | 74 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/ext/sockets/sockaddr_conv.c b/ext/sockets/sockaddr_conv.c index d007bf4af2ed0..d5365c36da2d8 100644 --- a/ext/sockets/sockaddr_conv.c +++ b/ext/sockets/sockaddr_conv.c @@ -11,24 +11,24 @@ extern zend_result php_string_to_if_index(const char *val, unsigned *out); -#ifdef HAVE_IPV6 -/* Sets addr by hostname, or by ip in string form (AF_INET6) */ -int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */ +int php_set_common_addr(struct sockaddr *sin, int family, char *string, php_socket *php_sock) /* {{{ */ { - struct in6_addr tmp; #ifdef HAVE_GETADDRINFO + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sin; + struct sockaddr_in *sin4 = (struct sockaddr_in*)sin; + struct in6_addr tmp6; + struct in_addr tmp4; + struct addrinfo hints; struct addrinfo *addrinfo = NULL; -#endif - char *scope = strchr(string, '%'); - if (inet_pton(AF_INET6, string, &tmp)) { - memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr)); + if (family == AF_INET6 && inet_pton(AF_INET6, string, &tmp6)) { + memcpy(&(sin6->sin6_addr.s6_addr), &(tmp6.s6_addr), sizeof(struct in6_addr)); + } else if (family == AF_INET && inet_pton(AF_INET, string, &tmp4)) { + sin4->sin_addr.s_addr = tmp4.s_addr; } else { -#ifdef HAVE_GETADDRINFO - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET6; + hints.ai_family = family; #ifdef AI_V4MAPPED hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; #else @@ -43,21 +43,37 @@ int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_ #endif return 0; } - if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) { - php_error_docref(NULL, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket"); + if (addrinfo->ai_family != family) { + php_error_docref(NULL, E_WARNING, "Host lookup failed: Wrong address family returned for socket"); freeaddrinfo(addrinfo); return 0; } - memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr)); + if (addrinfo->ai_family == AF_INET6) { + memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr)); + } else if (addrinfo->ai_family == AF_INET) { + memcpy(&(sin4->sin_addr.s_addr), &((struct sockaddr_in*)(addrinfo->ai_addr))->sin_addr.s_addr, sizeof(struct in_addr)); + } freeaddrinfo(addrinfo); + } + return 1; #else - /* No IPv6 specific hostname resolution is available on this system? */ - php_error_docref(NULL, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system"); - return 0; + php_error_docref(NULL, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system"); + return 0; #endif +} +/* }}} */ + +#ifdef HAVE_IPV6 +/* Sets addr by hostname, or by ip in string form (AF_INET6) */ +int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */ +{ + char *scope = strchr(string, '%'); + int ret = php_set_common_addr((struct sockaddr*)sin6, AF_INET6, string, php_sock); + if (!ret) { + return 0; } if (scope) { @@ -86,29 +102,7 @@ int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_ /* Sets addr by hostname, or by ip in string form (AF_INET) */ int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock) /* {{{ */ { - struct in_addr tmp; - struct hostent *host_entry; - - if (inet_pton(AF_INET, string, &tmp)) { - sin->sin_addr.s_addr = tmp.s_addr; - } else { - if (strlen(string) > MAXFQDNLEN || ! (host_entry = php_network_gethostbyname(string))) { - /* Note: < -10000 indicates a host lookup error */ -#ifdef PHP_WIN32 - PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError()); -#else - PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno)); -#endif - return 0; - } - if (host_entry->h_addrtype != AF_INET) { - php_error_docref(NULL, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket"); - return 0; - } - memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length); - } - - return 1; + return php_set_common_addr((struct sockaddr*)sin, AF_INET, string, php_sock); } /* }}} */ From 84b8214521c3d06189253c3cea9016f53e7fdfd0 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 12:21:01 -0300 Subject: [PATCH 04/17] Convert fastcgi listen to use getaddrinfo This is curiously IPv4 only, so I kept the the same semantics. --- main/fastcgi.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/main/fastcgi.c b/main/fastcgi.c index 448576a978598..403595947b5d5 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -682,21 +682,30 @@ int fcgi_listen(const char *path, int backlog) sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY); } else { if (!inet_pton(AF_INET, host, &sa.sa_inet.sin_addr)) { - struct hostent *hep; + struct sockaddr **addresses = NULL; + int address_count; - if(strlen(host) > MAXFQDNLEN) { - hep = NULL; + if (strlen(host) > MAXFQDNLEN) { + address_count = 0; } else { - hep = php_network_gethostbyname(host); + zend_string *gai_error = NULL; + address_count = php_network_getaddresses_ex(host, 0, AF_INET, 0, &addresses, &gai_error); + if (gai_error) { + zend_string_release_ex(gai_error, 0); + } } - if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) { + if (address_count == 0 || (*addresses)->sa_family != AF_INET) { fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host); + php_network_freeaddresses(addresses); return -1; - } else if (hep->h_addr_list[1]) { + } else if (address_count > 1) { fcgi_log(FCGI_ERROR, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host); + php_network_freeaddresses(addresses); return -1; } - sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr; + struct sockaddr_in *address4 = (struct sockaddr_in*)*addresses; + sa.sa_inet.sin_addr.s_addr = address4->sin_addr.s_addr; + php_network_freeaddresses(addresses); } } } else { From 5dcd07605373064edb84d1aa23b3278da64a96d0 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 12:50:20 -0300 Subject: [PATCH 05/17] Provide function for resolving a single address A common idiom is only caring about the first IP address, for i.e. resolving localhost -> 127.0.0.1/::1. Iterating through and freeing the whole list in this case is tedious. In this case, we provide a function that takes a pointer to a sockaddr storage (so it can be stack allocated), as well as information like address family (for i.e. only IPv4 addresses). This should hopefully be only as boilerplate as gethostbyname was. --- ext/standard/dns.c | 27 ++++++--------------------- main/fastcgi.c | 11 ++++------- main/network.c | 28 ++++++++++++++++++++++++++++ main/php_network.h | 1 + 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/ext/standard/dns.c b/ext/standard/dns.c index a0b84afa3029c..52690dcdbc16a 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -232,9 +232,9 @@ PHP_FUNCTION(gethostbyname) RETURN_STRINGL(hostname, hostname_len); } - struct sockaddr **addresses = NULL; + php_sockaddr_storage resolved; zend_string *gai_error = NULL; - int address_count = php_network_getaddresses(hostname, 0, &addresses, &gai_error); + int address_count = php_network_getaddress(&resolved, hostname, 0, AF_INET, 0, &gai_error); if (gai_error) { zend_string_release_ex(gai_error, 0); } @@ -247,27 +247,12 @@ PHP_FUNCTION(gethostbyname) * Future behaviour change: This function is documented as only returning IPv4 * addresses. We should change this to return IPv6 addresses as well. */ - for (struct sockaddr **address_p = addresses; *address_p != NULL; address_p++) { - struct sockaddr *address = *address_p; - - if (address->sa_family != AF_INET) { - continue; - } - - struct sockaddr_in *address4 = (struct sockaddr_in*)address; - const char *ipaddr; - if (!(ipaddr = inet_ntop(AF_INET, &address4->sin_addr, addr4, INET_ADDRSTRLEN))) { - /* unlikely regarding (too) long hostname and protocols but checking still */ - php_error_docref(NULL, E_WARNING, "Host name to ip failed %s", hostname); - continue; - } else { - ipaddr_zs = zend_string_init(ipaddr, strlen(ipaddr), 0); - break; /* we take only first IP for this function */ - } + struct sockaddr_in *address4 = (struct sockaddr_in*)&resolved; + const char *ipaddr; + if (resolved.ss_family == AF_INET && (ipaddr = inet_ntop(AF_INET, &address4->sin_addr, addr4, INET_ADDRSTRLEN))) { + ipaddr_zs = zend_string_init(ipaddr, strlen(ipaddr), 0); } - php_network_freeaddresses(addresses); - if (ipaddr_zs == NULL) { php_error_docref(NULL, E_WARNING, "Host name to ip failed %s", hostname); RETURN_STRINGL(hostname, hostname_len); diff --git a/main/fastcgi.c b/main/fastcgi.c index 403595947b5d5..779e67bf1b1ec 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -682,30 +682,27 @@ int fcgi_listen(const char *path, int backlog) sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY); } else { if (!inet_pton(AF_INET, host, &sa.sa_inet.sin_addr)) { - struct sockaddr **addresses = NULL; + php_sockaddr_storage resolved; int address_count; if (strlen(host) > MAXFQDNLEN) { address_count = 0; } else { zend_string *gai_error = NULL; - address_count = php_network_getaddresses_ex(host, 0, AF_INET, 0, &addresses, &gai_error); + address_count = php_network_getaddress(&resolved, host, 0, AF_INET, 0, &gai_error); if (gai_error) { zend_string_release_ex(gai_error, 0); } } - if (address_count == 0 || (*addresses)->sa_family != AF_INET) { + if (address_count == 0 || resolved.ss_family != AF_INET) { fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host); - php_network_freeaddresses(addresses); return -1; } else if (address_count > 1) { fcgi_log(FCGI_ERROR, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host); - php_network_freeaddresses(addresses); return -1; } - struct sockaddr_in *address4 = (struct sockaddr_in*)*addresses; + struct sockaddr_in *address4 = (struct sockaddr_in*)&resolved; sa.sa_inet.sin_addr.s_addr = address4->sin_addr.s_addr; - php_network_freeaddresses(addresses); } } } else { diff --git a/main/network.c b/main/network.c index 49657a1397dab..e754bc1ceef55 100644 --- a/main/network.c +++ b/main/network.c @@ -279,6 +279,34 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka } /* }}} */ +/* {{{ php_network_getaddress + * Returns the number of addresses, and puts first address for a hostname in sockaddr. + */ +PHPAPI int php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string) +{ + struct sockaddr** addresses; + int address_count = php_network_getaddresses_ex(host, socktype, family, ai_flags, &addresses, error_string); + if (address_count == 0) { + return 0; + } + + /* + * we only care about the first address, hopefully getaddrinfo + * filtered to the one we want + */ + struct sockaddr *address = *addresses; + + int sa_size = address->sa_family == AF_INET6 + ? sizeof(struct sockaddr_in6) + : sizeof(struct sockaddr_in); + memcpy(sockaddr, address, sa_size); + +fail: + php_network_freeaddresses(addresses); + return address_count; +} +/* }}} */ + #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif diff --git a/main/php_network.h b/main/php_network.h index d71a878d220d6..95182bb6308dc 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -263,6 +263,7 @@ BEGIN_EXTERN_C() PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string); PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string); PHPAPI void php_network_freeaddresses(struct sockaddr **sal); +PHPAPI int php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string); PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, From c8d649e7397878ff349d7ae90d703c7a268e1e46 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 13:02:14 -0300 Subject: [PATCH 06/17] Don't bother storing the gai_strerror result The underlying php_network_getaddresses will docref this for us, so there's no point in taking a zend_string we don't have to do anything with. --- ext/standard/dns.c | 12 ++---------- main/fastcgi.c | 6 +----- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ext/standard/dns.c b/ext/standard/dns.c index 52690dcdbc16a..1da7d280c7275 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -233,11 +233,7 @@ PHP_FUNCTION(gethostbyname) } php_sockaddr_storage resolved; - zend_string *gai_error = NULL; - int address_count = php_network_getaddress(&resolved, hostname, 0, AF_INET, 0, &gai_error); - if (gai_error) { - zend_string_release_ex(gai_error, 0); - } + int address_count = php_network_getaddress(&resolved, hostname, 0, AF_INET, 0, NULL); if (address_count == 0) { /* don't need to docref here, getaddresses E_WARNINGs for us */ RETURN_STRINGL(hostname, hostname_len); @@ -280,11 +276,7 @@ PHP_FUNCTION(gethostbynamel) } struct sockaddr **addresses = NULL; - zend_string *gai_error = NULL; - int address_count = php_network_getaddresses(hostname, 0, &addresses, &gai_error); - if (gai_error) { - zend_string_release_ex(gai_error, 0); - } + int address_count = php_network_getaddresses(hostname, 0, &addresses, NULL); if (address_count == 0) { /* don't need to docref here, getaddresses E_WARNINGs for us */ RETURN_FALSE; diff --git a/main/fastcgi.c b/main/fastcgi.c index 779e67bf1b1ec..61af41ee48bec 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -688,11 +688,7 @@ int fcgi_listen(const char *path, int backlog) if (strlen(host) > MAXFQDNLEN) { address_count = 0; } else { - zend_string *gai_error = NULL; - address_count = php_network_getaddress(&resolved, host, 0, AF_INET, 0, &gai_error); - if (gai_error) { - zend_string_release_ex(gai_error, 0); - } + address_count = php_network_getaddress(&resolved, host, 0, AF_INET, 0, NULL); } if (address_count == 0 || resolved.ss_family != AF_INET) { fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host); From 68d1e194094b8b46646d1c06c8a3aecd37bdc47c Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 13:03:51 -0300 Subject: [PATCH 07/17] Convert php_open_listen_sock to use getaddrinfo Also curiously IPv4 only... --- ext/sockets/sockets.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 9e33f4e6cfdb7..4fea44428269c 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -220,18 +220,19 @@ ZEND_GET_MODULE(sockets) static bool php_open_listen_sock(php_socket *sock, int port, int backlog) /* {{{ */ { struct sockaddr_in la = {0}; - struct hostent *hp; + php_sockaddr_storage resolved; #ifndef PHP_WIN32 - if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) { + const char *hostname = "0.0.0.0"; #else - if ((hp = php_network_gethostbyname("localhost")) == NULL) { + const char *hostname = "localhost"; #endif + + if (php_network_getaddress(&resolved, hostname, SOCK_STREAM, AF_INET, 0, NULL) == 0 || resolved.ss_family != AF_INET) { return 0; } - memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length); - la.sin_family = hp->h_addrtype; + memcpy(&la, &resolved, sizeof(struct sockaddr_in)); la.sin_port = htons((unsigned short) port); sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0); From 62531294d1a84accbbaa424b173f190360d051dc Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 13:52:58 -0300 Subject: [PATCH 08/17] Remove remnant of refactor --- main/network.c | 1 - 1 file changed, 1 deletion(-) diff --git a/main/network.c b/main/network.c index e754bc1ceef55..49998c422262a 100644 --- a/main/network.c +++ b/main/network.c @@ -301,7 +301,6 @@ PHPAPI int php_network_getaddress(php_sockaddr_storage *sockaddr, const char *ho : sizeof(struct sockaddr_in); memcpy(sockaddr, address, sa_size); -fail: php_network_freeaddresses(addresses); return address_count; } From 8556fdf1c25643dbf65f51858eaf150bb41556c2 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 14:12:20 -0300 Subject: [PATCH 09/17] Convert sockaddr conv to use bool --- ext/sockets/conversions.c | 4 ++-- ext/sockets/sockaddr_conv.c | 26 +++++++++++++------------- ext/sockets/sockaddr_conv.h | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index 04dad88ac5915..906860562c76e 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -550,7 +550,7 @@ static void to_zval_read_uid_t(const char *data, zval *zv, res_context *ctx) /* CONVERSIONS for sockaddr */ static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx) { - int res; + bool res; struct sockaddr_in saddr = {0}; zend_string *addr_str, *tmp_addr_str; @@ -600,7 +600,7 @@ static void to_zval_read_sockaddr_in(const char *data, zval *zv, res_context *ct #ifdef HAVE_IPV6 static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx) { - int res; + bool res; struct sockaddr_in6 saddr6 = {0}; zend_string *addr_str, *tmp_addr_str; diff --git a/ext/sockets/sockaddr_conv.c b/ext/sockets/sockaddr_conv.c index d5365c36da2d8..6be3f0a0eed2b 100644 --- a/ext/sockets/sockaddr_conv.c +++ b/ext/sockets/sockaddr_conv.c @@ -11,7 +11,7 @@ extern zend_result php_string_to_if_index(const char *val, unsigned *out); -int php_set_common_addr(struct sockaddr *sin, int family, char *string, php_socket *php_sock) /* {{{ */ +bool php_set_common_addr(struct sockaddr *sin, int family, char *string, php_socket *php_sock) /* {{{ */ { #ifdef HAVE_GETADDRINFO struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sin; @@ -41,12 +41,12 @@ int php_set_common_addr(struct sockaddr *sin, int family, char *string, php_sock #else PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno)); #endif - return 0; + return false; } if (addrinfo->ai_family != family) { php_error_docref(NULL, E_WARNING, "Host lookup failed: Wrong address family returned for socket"); freeaddrinfo(addrinfo); - return 0; + return false; } if (addrinfo->ai_family == AF_INET6) { @@ -57,23 +57,23 @@ int php_set_common_addr(struct sockaddr *sin, int family, char *string, php_sock freeaddrinfo(addrinfo); } - return 1; + return true; #else php_error_docref(NULL, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system"); - return 0; + return true; #endif } /* }}} */ #ifdef HAVE_IPV6 /* Sets addr by hostname, or by ip in string form (AF_INET6) */ -int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */ +bool php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */ { char *scope = strchr(string, '%'); - int ret = php_set_common_addr((struct sockaddr*)sin6, AF_INET6, string, php_sock); + bool ret = php_set_common_addr((struct sockaddr*)sin6, AF_INET6, string, php_sock); if (!ret) { - return 0; + return false; } if (scope) { @@ -100,7 +100,7 @@ int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_ #endif /* Sets addr by hostname, or by ip in string form (AF_INET) */ -int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock) /* {{{ */ +bool php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock) /* {{{ */ { return php_set_common_addr((struct sockaddr*)sin, AF_INET, string, php_sock); } @@ -108,7 +108,7 @@ int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_soc /* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6, * depending on the socket) */ -int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock) /* {{{ */ +bool php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock) /* {{{ */ { if (php_sock->type == AF_INET) { struct sockaddr_in t = {0}; @@ -116,7 +116,7 @@ int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *strin memcpy(ss, &t, sizeof t); ss->ss_family = AF_INET; *ss_len = sizeof(t); - return 1; + return true; } } #ifdef HAVE_IPV6 @@ -126,7 +126,7 @@ int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *strin memcpy(ss, &t, sizeof t); ss->ss_family = AF_INET6; *ss_len = sizeof(t); - return 1; + return true; } } #endif @@ -134,5 +134,5 @@ int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *strin php_error_docref(NULL, E_WARNING, "IP address used in the context of an unexpected type of socket"); } - return 0; + return false; } diff --git a/ext/sockets/sockaddr_conv.h b/ext/sockets/sockaddr_conv.h index 1e7e3cf046d0a..50de76713690c 100644 --- a/ext/sockets/sockaddr_conv.h +++ b/ext/sockets/sockaddr_conv.h @@ -16,16 +16,16 @@ * The IPv6 literal can be a IPv4 mapped address (like ::ffff:127.0.0.1). * If the hostname yields no IPv6 addresses, a mapped IPv4 address may be returned (AI_V4MAPPED) */ -int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock); +bool php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock); /* * Convert an IPv4 literal or a hostname into a sockaddr_in. */ -int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock); +bool php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock); /* * Calls either php_set_inet6_addr() or php_set_inet_addr(), depending on the type of the socket. */ -int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock); +bool php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock); #endif From 16cd84af882e0a77c3e41f0640f40509ac1ee4e6 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 14:25:19 -0300 Subject: [PATCH 10/17] Remove getaddrinfo->gethostbyname fallback We will no longer be using this function. --- main/network.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/main/network.c b/main/network.c index 49998c422262a..096699d2c06ff 100644 --- a/main/network.c +++ b/main/network.c @@ -233,36 +233,7 @@ PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int famil freeaddrinfo(res); #else - if (!inet_pton(AF_INET, host, &in)) { - if(strlen(host) > MAXFQDNLEN) { - host_info = NULL; - errno = E2BIG; - } else { - host_info = php_network_gethostbyname(host); - } - if (host_info == NULL) { - if (error_string) { - /* free error string received during previous iteration (if any) */ - if (*error_string) { - zend_string_release_ex(*error_string, 0); - } - *error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno); - php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string)); - } else { - php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed"); - } - return 0; - } - in = *((struct in_addr *) host_info->h_addr); - } - - *sal = safe_emalloc(2, sizeof(*sal), 0); - sap = *sal; - *sap = emalloc(sizeof(struct sockaddr_in)); - (*sap)->sa_family = AF_INET; - ((struct sockaddr_in *)*sap)->sin_addr = in; - sap++; - n = 1; + php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo() not available on this system"); #endif *sap = NULL; From 41c590b21473f8ecf05dbba57e62a2f898a0a094 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 14:28:36 -0300 Subject: [PATCH 11/17] Remove gethostbyname from ABI (mostly) Callers should use php_network_getaddress* instead. --- build/ax_func_which_gethostbyname_r.m4 | 196 ------------------------- configure.ac | 1 - main/network.c | 88 ----------- main/php_network.h | 2 - 4 files changed, 287 deletions(-) delete mode 100644 build/ax_func_which_gethostbyname_r.m4 diff --git a/build/ax_func_which_gethostbyname_r.m4 b/build/ax_func_which_gethostbyname_r.m4 deleted file mode 100644 index bb6bc959e7074..0000000000000 --- a/build/ax_func_which_gethostbyname_r.m4 +++ /dev/null @@ -1,196 +0,0 @@ -# ================================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_func_which_gethostbyname_r.html -# ================================================================================== -# -# SYNOPSIS -# -# AX_FUNC_WHICH_GETHOSTBYNAME_R -# -# DESCRIPTION -# -# Determines which historical variant of the gethostbyname_r() call -# (taking three, five, or six arguments) is available on the system and -# defines one of the following macros accordingly: -# -# HAVE_FUNC_GETHOSTBYNAME_R_6 -# HAVE_FUNC_GETHOSTBYNAME_R_5 -# HAVE_FUNC_GETHOSTBYNAME_R_3 -# -# as well as -# -# HAVE_GETHOSTBYNAME_R -# -# If used in conjunction with gethostname.c, the API demonstrated in -# test.c can be used regardless of which gethostbyname_r() is available. -# These example files can be found at -# http://www.csn.ul.ie/~caolan/publink/gethostbyname_r -# -# based on David Arnold's autoconf suggestion in the threads faq -# -# Originally named "AC_caolan_FUNC_WHICH_GETHOSTBYNAME_R". Rewritten for -# Autoconf 2.5x, and updated for 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Caolan McNamara -# Copyright (c) 2008 Daniel Richard G. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 8 - -AC_DEFUN([AX_FUNC_WHICH_GETHOSTBYNAME_R], [ - - AC_LANG_PUSH([C]) - AC_MSG_CHECKING([how many arguments gethostbyname_r() takes]) - - AC_CACHE_VAL([ac_cv_func_which_gethostbyname_r], [ - -################################################################ - -ac_cv_func_which_gethostbyname_r=unknown - -# -# ONE ARGUMENT (sanity check) -# - -# This should fail, as there is no variant of gethostbyname_r() that takes -# a single argument. If it actually compiles, then we can assume that -# netdb.h is not declaring the function, and the compiler is thereby -# assuming an implicit prototype. In which case, we're out of luck. -# -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], - [ - char *name = "www.gnu.org"; - (void)gethostbyname_r(name) /* ; */ - ])], - [ac_cv_func_which_gethostbyname_r=no]) - -# -# SIX ARGUMENTS -# (e.g. Linux) -# - -if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then - -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], - [ - char *name = "www.gnu.org"; - struct hostent ret, *retp; - char buf@<:@1024@:>@; - int buflen = 1024; - int my_h_errno; - (void)gethostbyname_r(name, &ret, buf, buflen, &retp, &my_h_errno) /* ; */ - ])], - [ac_cv_func_which_gethostbyname_r=six]) - -fi - -# -# FIVE ARGUMENTS -# (e.g. Solaris) -# - -if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then - -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], - [ - char *name = "www.gnu.org"; - struct hostent ret; - char buf@<:@1024@:>@; - int buflen = 1024; - int my_h_errno; - (void)gethostbyname_r(name, &ret, buf, buflen, &my_h_errno) /* ; */ - ])], - [ac_cv_func_which_gethostbyname_r=five]) - -fi - -# -# THREE ARGUMENTS -# (e.g. AIX, HP-UX, Tru64) -# - -if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then - -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], - [ - char *name = "www.gnu.org"; - struct hostent ret; - struct hostent_data data; - (void)gethostbyname_r(name, &ret, &data) /* ; */ - ])], - [ac_cv_func_which_gethostbyname_r=three]) - -fi - -################################################################ - -]) dnl end AC_CACHE_VAL - -case "$ac_cv_func_which_gethostbyname_r" in - three|five|six) - AC_DEFINE([HAVE_GETHOSTBYNAME_R], [1], - [Define to 1 if you have some form of gethostbyname_r().]) - ;; -esac - -case "$ac_cv_func_which_gethostbyname_r" in - three) - AC_MSG_RESULT([three]) - AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_3], [1], - [Define to 1 if you have the three-argument form of gethostbyname_r().]) - ;; - - five) - AC_MSG_RESULT([five]) - AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_5], [1], - [Define to 1 if you have the five-argument form of gethostbyname_r().]) - ;; - - six) - AC_MSG_RESULT([six]) - AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_6], [1], - [Define to 1 if you have the six-argument form of gethostbyname_r().]) - ;; - - no) - AC_MSG_RESULT([cannot find function declaration in netdb.h]) - ;; - - unknown) - AC_MSG_RESULT([can't tell]) - ;; - - *) - AC_MSG_ERROR([internal error]) - ;; -esac - -AC_LANG_POP - -]) dnl end AC_DEFUN diff --git a/configure.ac b/configure.ac index 904786aca432d..0897bf069e3d7 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,6 @@ dnl Include external macro definitions before the AC_INIT to also remove dnl comments starting with # and empty newlines from the included files. dnl ---------------------------------------------------------------------------- m4_include([build/ax_check_compile_flag.m4]) -m4_include([build/ax_func_which_gethostbyname_r.m4]) m4_include([build/ax_gcc_func_attribute.m4]) m4_include([build/libtool.m4]) m4_include([build/php_cxx_compile_stdcxx.m4]) diff --git a/main/network.c b/main/network.c index 096699d2c06ff..b385b42d8094f 100644 --- a/main/network.c +++ b/main/network.c @@ -1240,91 +1240,3 @@ PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout) return n; } #endif - -#if defined(HAVE_GETHOSTBYNAME_R) -#ifdef HAVE_FUNC_GETHOSTBYNAME_R_6 -static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) -{ - struct hostent *hp; - int herr,res; - - if (*hstbuflen == 0) { - *hstbuflen = 1024; - *tmphstbuf = (char *)malloc (*hstbuflen); - } - - while (( res = - gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr)) - && (errno == ERANGE)) { - /* Enlarge the buffer. */ - *hstbuflen *= 2; - *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); - } - - if (res != 0) { - return NULL; - } - - return hp; -} -#endif -#ifdef HAVE_FUNC_GETHOSTBYNAME_R_5 -static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) -{ - struct hostent *hp; - int herr; - - if (*hstbuflen == 0) { - *hstbuflen = 1024; - *tmphstbuf = (char *)malloc (*hstbuflen); - } - - while ((NULL == ( hp = - gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr))) - && (errno == ERANGE)) { - /* Enlarge the buffer. */ - *hstbuflen *= 2; - *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); - } - return hp; -} -#endif -#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3 -static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) -{ - if (*hstbuflen == 0) { - *hstbuflen = sizeof(struct hostent_data); - *tmphstbuf = (char *)malloc (*hstbuflen); - } else { - if (*hstbuflen < sizeof(struct hostent_data)) { - *hstbuflen = sizeof(struct hostent_data); - *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen); - } - } - memset((void *)(*tmphstbuf),0,*hstbuflen); - - if (0 != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) { - return NULL; - } - - return hostbuf; -} -#endif -#endif - -PHPAPI struct hostent* php_network_gethostbyname(const char *name) { -#if !defined(HAVE_GETHOSTBYNAME_R) - return gethostbyname(name); -#else - if (FG(tmp_host_buf)) { - free(FG(tmp_host_buf)); - } - - FG(tmp_host_buf) = NULL; - FG(tmp_host_buf_len) = 0; - - memset(&FG(tmp_host_info), 0, sizeof(struct hostent)); - - return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len)); -#endif -} diff --git a/main/php_network.h b/main/php_network.h index 95182bb6308dc..b6909047a5eb5 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -341,8 +341,6 @@ PHPAPI void php_network_populate_name_from_sockaddr( PHPAPI zend_result php_network_parse_network_address_with_port(const char *addr, size_t addrlen, struct sockaddr *sa, socklen_t *sl); -PHPAPI struct hostent* php_network_gethostbyname(const char *name); - PHPAPI zend_result php_set_sock_blocking(php_socket_t socketd, bool block); END_EXTERN_C() From c4efccd2513ee8aaf5913f56eb4d0234f7025811 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 14:40:51 -0300 Subject: [PATCH 12/17] Convert php_network_getaddress* to use unsigned size_t Since this can never return -1 (0 on error/none, >0 for addresses) --- ext/snmp/snmp.c | 2 +- ext/standard/dns.c | 4 ++-- main/fastcgi.c | 2 +- main/network.c | 17 +++++++++-------- main/php_network.h | 6 +++--- sapi/cli/php_cli_server.c | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 7e8d4d0bc2fc1..caa6ea02da109 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -792,7 +792,7 @@ static bool netsnmp_session_init(php_snmp_session **session_p, int version, zend php_snmp_session *session; char *pptr, *host_ptr; bool force_ipv6 = false; - int n; + size_t n; struct sockaddr **psal; struct sockaddr **res; // TODO: Do not strip and re-add the port in peername? diff --git a/ext/standard/dns.c b/ext/standard/dns.c index 1da7d280c7275..4786bac02c4cc 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -233,7 +233,7 @@ PHP_FUNCTION(gethostbyname) } php_sockaddr_storage resolved; - int address_count = php_network_getaddress(&resolved, hostname, 0, AF_INET, 0, NULL); + size_t address_count = php_network_getaddress(&resolved, hostname, 0, AF_INET, 0, NULL); if (address_count == 0) { /* don't need to docref here, getaddresses E_WARNINGs for us */ RETURN_STRINGL(hostname, hostname_len); @@ -276,7 +276,7 @@ PHP_FUNCTION(gethostbynamel) } struct sockaddr **addresses = NULL; - int address_count = php_network_getaddresses(hostname, 0, &addresses, NULL); + size_t address_count = php_network_getaddresses(hostname, 0, &addresses, NULL); if (address_count == 0) { /* don't need to docref here, getaddresses E_WARNINGs for us */ RETURN_FALSE; diff --git a/main/fastcgi.c b/main/fastcgi.c index 61af41ee48bec..85e4348412e4c 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -683,7 +683,7 @@ int fcgi_listen(const char *path, int backlog) } else { if (!inet_pton(AF_INET, host, &sa.sa_inet.sin_addr)) { php_sockaddr_storage resolved; - int address_count; + size_t address_count; if (strlen(host) > MAXFQDNLEN) { address_count = 0; diff --git a/main/network.c b/main/network.c index b385b42d8094f..87c56116c1d1f 100644 --- a/main/network.c +++ b/main/network.c @@ -146,10 +146,11 @@ PHPAPI void php_network_freeaddresses(struct sockaddr **sal) /* {{{ php_network_getaddresses_ex * Returns number of addresses, 0 for none/error */ -PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string) +PHPAPI size_t php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string) { struct sockaddr **sap; - int n; + size_t n; + int ret; #ifdef HAVE_GETADDRINFO # ifdef HAVE_IPV6 static int ipv6_borked = -1; /* the way this is used *is* thread safe */ @@ -191,16 +192,16 @@ PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int famil hints.ai_family = ipv6_borked ? AF_INET : family; # endif - if ((n = getaddrinfo(host, NULL, &hints, &res))) { + if ((ret = getaddrinfo(host, NULL, &hints, &res))) { if (error_string) { /* free error string received during previous iteration (if any) */ if (*error_string) { zend_string_release_ex(*error_string, 0); } - *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(n)); + *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(ret)); php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string)); } else { - php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(n)); + php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(ret)); } return 0; } else if (res == NULL) { @@ -244,7 +245,7 @@ PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int famil /* {{{ php_network_getaddresses * Returns number of addresses, 0 for none/error */ -PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string) +PHPAPI size_t php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string) { return php_network_getaddresses_ex(host, socktype, AF_UNSPEC, 0, sal, error_string); } @@ -253,10 +254,10 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka /* {{{ php_network_getaddress * Returns the number of addresses, and puts first address for a hostname in sockaddr. */ -PHPAPI int php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string) +PHPAPI size_t php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string) { struct sockaddr** addresses; - int address_count = php_network_getaddresses_ex(host, socktype, family, ai_flags, &addresses, error_string); + size_t address_count = php_network_getaddresses_ex(host, socktype, family, ai_flags, &addresses, error_string); if (address_count == 0) { return 0; } diff --git a/main/php_network.h b/main/php_network.h index b6909047a5eb5..ec33b991af31f 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -260,10 +260,10 @@ typedef struct { #endif BEGIN_EXTERN_C() -PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string); -PHPAPI int php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string); +PHPAPI size_t php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string); +PHPAPI size_t php_network_getaddresses_ex(const char *host, int socktype, int family, int ai_flags, struct sockaddr ***sal, zend_string **error_string); PHPAPI void php_network_freeaddresses(struct sockaddr **sal); -PHPAPI int php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string); +PHPAPI size_t php_network_getaddress(php_sockaddr_storage *sockaddr, const char *host, int socktype, int family, int ai_flags, zend_string **error_string); PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index a720ce32e356c..58c7735e60c8a 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1286,7 +1286,7 @@ static php_socket_t php_network_listen_socket(const char *host, int *port, int s int err = 0; struct sockaddr *sa = NULL, **p, **sal; - int num_addrs = php_network_getaddresses(host, socktype, &sal, errstr); + size_t num_addrs = php_network_getaddresses(host, socktype, &sal, errstr); if (num_addrs == 0) { return -1; } From b6c219b99f7697970f271c210d3757b981f5f14b Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 14:45:32 -0300 Subject: [PATCH 13/17] Clean up remaining gethostbyname(_r) detritus Includes some global state as well. --- configure.ac | 2 -- ext/standard/file.c | 5 ----- ext/standard/file.h | 5 ----- main/php_network.h | 2 +- 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 0897bf069e3d7..85f666bc85a71 100644 --- a/configure.ac +++ b/configure.ac @@ -599,8 +599,6 @@ dnl Check for functions inside their belonging headers. AC_CHECK_HEADER([sys/prctl.h], [AC_CHECK_FUNCS([prctl])]) AC_CHECK_HEADER([sys/procctl.h], [AC_CHECK_FUNCS([procctl])]) -AX_FUNC_WHICH_GETHOSTBYNAME_R - dnl Some systems (Solaris 10) do not have nanosleep in libc. AC_CHECK_FUNCS([nanosleep],, [AC_SEARCH_LIBS([nanosleep], [rt], [AC_DEFINE([HAVE_NANOSLEEP], [1])])]) diff --git a/ext/standard/file.c b/ext/standard/file.c index 6b6b43b1fb672..c44d8bb127e20 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -136,11 +136,6 @@ static void file_globals_ctor(php_file_globals *file_globals_p) static void file_globals_dtor(php_file_globals *file_globals_p) { -#if defined(HAVE_GETHOSTBYNAME_R) - if (file_globals_p->tmp_host_buf) { - free(file_globals_p->tmp_host_buf); - } -#endif } static PHP_INI_MH(OnUpdateAutoDetectLineEndings) diff --git a/ext/standard/file.h b/ext/standard/file.h index eead935848877..0baf51d3a170b 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -102,11 +102,6 @@ typedef struct { HashTable *stream_filters; /* per-request copy of stream_filters_hash */ HashTable *wrapper_errors; /* key: wrapper address; value: linked list of char* */ int pclose_wait; -#ifdef HAVE_GETHOSTBYNAME_R - struct hostent tmp_host_info; - char *tmp_host_buf; - size_t tmp_host_buf_len; -#endif } php_file_globals; #ifdef ZTS diff --git a/main/php_network.h b/main/php_network.h index ec33b991af31f..fbc7c4affea03 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -76,7 +76,7 @@ END_EXTERN_C() #include #endif -#ifdef HAVE_GETHOSTBYNAME_R +#ifndef PHP_WIN32 #include #endif From 500f68c8051aa07ea4b324361a48eacea80ac269 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 16:32:29 -0300 Subject: [PATCH 14/17] gai_strerror will return differently per platform --- ext/standard/tests/network/gethostbyname_error003.phpt | 2 +- ext/standard/tests/network/gethostbyname_error006.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/network/gethostbyname_error003.phpt b/ext/standard/tests/network/gethostbyname_error003.phpt index 47ae902bb4ad2..4e16fccba8775 100644 --- a/ext/standard/tests/network/gethostbyname_error003.phpt +++ b/ext/standard/tests/network/gethostbyname_error003.phpt @@ -7,5 +7,5 @@ gethostbyname() function - basic type return error test var_dump(is_string(gethostbyname("asdfasdf"))); ?> --EXPECTF-- -Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for asdfasdf failed: nodename nor servname provided, or not known in %s on line %d +Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for asdfasdf failed: %s in %s on line %d bool(true) diff --git a/ext/standard/tests/network/gethostbyname_error006.phpt b/ext/standard/tests/network/gethostbyname_error006.phpt index 764f3fce5c5d1..9b667e63cbdda 100644 --- a/ext/standard/tests/network/gethostbyname_error006.phpt +++ b/ext/standard/tests/network/gethostbyname_error006.phpt @@ -7,5 +7,5 @@ gethostbyname() function - basic invalid parameter test var_dump(gethostbyname(".toto.toto.toto")); ?> --EXPECTF-- -Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for .toto.toto.toto failed: nodename nor servname provided, or not known in %s on line %d +Warning: gethostbyname(): php_network_getaddresses: getaddrinfo for .toto.toto.toto failed: %s in %s on line %d string(15) ".toto.toto.toto" From 8fb90025592eac94a5fc30f120e62c3201dfbf11 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 16:34:00 -0300 Subject: [PATCH 15/17] getaddrinfo emits warnings now for failures to resolve this borks curl tests, so supress warnings on it there --- ext/curl/tests/curl_basic_008.phpt | 2 +- ext/curl/tests/curl_basic_010.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/curl/tests/curl_basic_008.phpt b/ext/curl/tests/curl_basic_008.phpt index 353c44327c5e8..c692713074f59 100644 --- a/ext/curl/tests/curl_basic_008.phpt +++ b/ext/curl/tests/curl_basic_008.phpt @@ -7,7 +7,7 @@ curl --SKIPIF-- diff --git a/ext/curl/tests/curl_basic_010.phpt b/ext/curl/tests/curl_basic_010.phpt index 7920408dc5534..257b1182e0530 100644 --- a/ext/curl/tests/curl_basic_010.phpt +++ b/ext/curl/tests/curl_basic_010.phpt @@ -7,7 +7,7 @@ curl --SKIPIF-- From 3dbfdf57fe6423be1986052418f2e2411d7d943b Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 23 Aug 2024 21:56:44 -0300 Subject: [PATCH 16/17] Remove old file submodule dtor --- ext/standard/basic_functions.c | 1 - ext/standard/file.c | 15 +-------------- ext/standard/file.h | 1 - 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 67276adb1627e..20a355aaa8639 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -382,7 +382,6 @@ PHP_MSHUTDOWN_FUNCTION(basic) /* {{{ */ BASIC_MSHUTDOWN_SUBMODULE(array) BASIC_MSHUTDOWN_SUBMODULE(assert) BASIC_MSHUTDOWN_SUBMODULE(url_scanner_ex) - BASIC_MSHUTDOWN_SUBMODULE(file) BASIC_MSHUTDOWN_SUBMODULE(standard_filters) #ifdef ZTS BASIC_MSHUTDOWN_SUBMODULE(localeconv) diff --git a/ext/standard/file.c b/ext/standard/file.c index c44d8bb127e20..a1fa9f7e02c6f 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -134,10 +134,6 @@ static void file_globals_ctor(php_file_globals *file_globals_p) file_globals_p->def_chunk_size = PHP_SOCK_CHUNK_SIZE; } -static void file_globals_dtor(php_file_globals *file_globals_p) -{ -} - static PHP_INI_MH(OnUpdateAutoDetectLineEndings) { if (zend_ini_parse_bool(new_value)) { @@ -158,7 +154,7 @@ PHP_MINIT_FUNCTION(file) le_stream_context = zend_register_list_destructors_ex(file_context_dtor, NULL, "stream-context", module_number); #ifdef ZTS - ts_allocate_id(&file_globals_id, sizeof(php_file_globals), (ts_allocate_ctor) file_globals_ctor, (ts_allocate_dtor) file_globals_dtor); + ts_allocate_id(&file_globals_id, sizeof(php_file_globals), (ts_allocate_ctor) file_globals_ctor, (ts_allocate_dtor) NULL); #else file_globals_ctor(&file_globals); #endif @@ -171,15 +167,6 @@ PHP_MINIT_FUNCTION(file) } /* }}} */ -PHP_MSHUTDOWN_FUNCTION(file) /* {{{ */ -{ -#ifndef ZTS - file_globals_dtor(&file_globals); -#endif - return SUCCESS; -} -/* }}} */ - PHPAPI void php_flock_common(php_stream *stream, zend_long operation, uint32_t operation_arg_num, zval *wouldblock, zval *return_value) { diff --git a/ext/standard/file.h b/ext/standard/file.h index 0baf51d3a170b..278d28e747ada 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -20,7 +20,6 @@ #include "php_network.h" PHP_MINIT_FUNCTION(file); -PHP_MSHUTDOWN_FUNCTION(file); PHPAPI PHP_FUNCTION(fclose); PHPAPI PHP_FUNCTION(feof); From 7267213c14cf54467f4f715e4e29ba8c4d24f77e Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Sat, 24 Aug 2024 14:57:42 -0300 Subject: [PATCH 17/17] Actually use the returned value It seems on Unix, the behaviour is to convert integers into IP addresses, whereas Windows tries to resolve it. Regardless, it's silly to test what the type is, since it returns the unmodified hostname if it can't be resolved, so it'll always be a string, error or not. --- ext/standard/tests/network/gethostbyname_error002.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/network/gethostbyname_error002.phpt b/ext/standard/tests/network/gethostbyname_error002.phpt index 8f586d02ba8b2..cd4d25625f7fc 100644 --- a/ext/standard/tests/network/gethostbyname_error002.phpt +++ b/ext/standard/tests/network/gethostbyname_error002.phpt @@ -4,7 +4,7 @@ gethostbyname() function - basic type return error test "Sylvain R." --FILE-- --EXPECT-- -bool(true) +string(12) "73.150.2.210"