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..85f666bc85a71 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]) @@ -600,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/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-- 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/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 d007bf4af2ed0..6be3f0a0eed2b 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) /* {{{ */ +bool 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 @@ -41,23 +41,39 @@ int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_ #else PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno)); #endif - return 0; + return false; } - 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; + return false; } - 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 true; #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 true; #endif +} +/* }}} */ + +#ifdef HAVE_IPV6 +/* Sets addr by hostname, or by ip in string form (AF_INET6) */ +bool php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */ +{ + char *scope = strchr(string, '%'); + bool ret = php_set_common_addr((struct sockaddr*)sin6, AF_INET6, string, php_sock); + if (!ret) { + return false; } if (scope) { @@ -84,37 +100,15 @@ 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) /* {{{ */ { - 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); } /* }}} */ /* 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}; @@ -122,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 @@ -132,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 @@ -140,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 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); 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/dns.c b/ext/standard/dns.c index 04477129e3599..4786bac02c4cc 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,28 @@ PHP_FUNCTION(gethostbyname) RETURN_STRINGL(hostname, hostname_len); } - if (!(ipaddr = php_gethostbyname(hostname))) { + php_sockaddr_storage resolved; + 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); + } + + /* + * Future behaviour change: This function is documented as only returning IPv4 + * addresses. We should change this to return IPv6 addresses as well. + */ + 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); + } + + 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 +263,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 +275,29 @@ PHP_FUNCTION(gethostbynamel) RETURN_FALSE; } - hp = php_network_gethostbyname(hostname); - if (!hp) { + struct sockaddr **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; } 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 +305,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/file.c b/ext/standard/file.c index 6b6b43b1fb672..a1fa9f7e02c6f 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -134,15 +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) -{ -#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) { if (zend_ini_parse_bool(new_value)) { @@ -163,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 @@ -176,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 eead935848877..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); @@ -102,11 +101,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/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" diff --git a/ext/standard/tests/network/gethostbyname_error003.phpt b/ext/standard/tests/network/gethostbyname_error003.phpt index ebc8a971cb016..4e16fccba8775 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: %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 156ba0e623c30..9b667e63cbdda 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: %s in %s on line %d string(15) ".toto.toto.toto" diff --git a/main/fastcgi.c b/main/fastcgi.c index 448576a978598..85e4348412e4c 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -682,21 +682,23 @@ 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; + php_sockaddr_storage resolved; + size_t address_count; - if(strlen(host) > MAXFQDNLEN) { - hep = NULL; + if (strlen(host) > MAXFQDNLEN) { + address_count = 0; } else { - hep = php_network_gethostbyname(host); + address_count = php_network_getaddress(&resolved, host, 0, AF_INET, 0, NULL); } - if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) { + if (address_count == 0 || resolved.ss_family != AF_INET) { fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host); 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); 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*)&resolved; + sa.sa_inet.sin_addr.s_addr = address4->sin_addr.s_addr; } } } else { diff --git a/main/network.c b/main/network.c index bf34043362dab..87c56116c1d1f 100644 --- a/main/network.c +++ b/main/network.c @@ -143,13 +143,14 @@ 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 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 */ @@ -168,6 +169,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,19 +189,19 @@ 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))) { + 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) { @@ -232,36 +234,7 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka 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; @@ -269,6 +242,42 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka } /* }}} */ +/* {{{ php_network_getaddresses + * Returns number of addresses, 0 for none/error + */ +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); +} +/* }}} */ + +/* {{{ php_network_getaddress + * Returns the number of addresses, and puts first address for a hostname in sockaddr. + */ +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; + size_t 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); + + php_network_freeaddresses(addresses); + return address_count; +} +/* }}} */ + #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif @@ -1232,91 +1241,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 06da95dd68ce6..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 @@ -260,8 +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 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 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, @@ -339,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() 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; }