1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix bug #67563: mysqli compiled with mysqlnd does not take ipv6 adress as parameter

In the past, when libmysqlclient could be used, it accepted ipv6 addresses
as hostname without enclosing it first in brackets. However, in mysqlnd
this never worked. In the past this caused a discrepancy between the two
implementations.
Nowadays, mysqli only works with mysqlnd so we don't even have to cater
to libmysqlclient. However, a plain ipv6 address should still work as a
hostname. Also for people migrating to newer PHP versions it's nice if
this keeps working.

The solution is to check if we're dealing with an ipv6 address not yet
enclosed in brackets. In that case we add the brackets automatically.

Closes GH-19750.
This commit is contained in:
Niels Dossche
2025-09-07 21:08:10 +02:00
parent 21c2c07a24
commit 6db12e7cd8
3 changed files with 61 additions and 1 deletions

4
NEWS
View File

@@ -30,6 +30,10 @@ PHP NEWS
- GD:
. FIxed GH-19955 (imagefttext() memory leak). (David Carlier)
- MySQLnd:
. Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress
as parameter). (nielsdos)
- SimpleXML:
. Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)).
(nielsdos)

View File

@@ -0,0 +1,40 @@
--TEST--
Fix bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress as parameter)
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once 'connect.inc';
if ($host !== '127.0.0.1')
die('skip local test');
if (@stream_socket_client('udp://[::1]:8888') === false)
die('skip no IPv6 support 2');
if (!$link = @my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
$host, $user, $db, $port, $socket));
}
?>
--INI--
max_execution_time=240
--FILE--
<?php
require_once 'connect.inc';
$hosts = ['::1', "[::1]:$port"];
foreach ($hosts as $host) {
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=%s dbname=%s, port=%s, socket=%s\n",
$host, $user, $passwd, $db, $port, $socket);
} else {
$link->close();
}
}
print "done!";
?>
--EXPECT--
done!

View File

@@ -513,6 +513,16 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn,
}
/* }}} */
/* ipv6 addresses have at least two colons, which is how we can differentiate between domain names and addresses */
static bool mysqlnd_fast_is_ipv6_address(const char *s)
{
const char *first_colon = strchr(s, ':');
if (!first_colon) {
return false;
}
return strchr(first_colon + 1, ':') != NULL;
}
/* {{{ mysqlnd_conn_data::get_scheme */
static MYSQLND_STRING
MYSQLND_METHOD(mysqlnd_conn_data, get_scheme)(MYSQLND_CONN_DATA * conn, MYSQLND_CSTRING hostname, MYSQLND_CSTRING *socket_or_pipe, unsigned int port, bool * unix_socket, bool * named_pipe)
@@ -542,7 +552,13 @@ MYSQLND_METHOD(mysqlnd_conn_data, get_scheme)(MYSQLND_CONN_DATA * conn, MYSQLND_
if (!port) {
port = 3306;
}
transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port);
/* ipv6 addresses are in the format [address]:port */
if (hostname.s[0] != '[' && mysqlnd_fast_is_ipv6_address(hostname.s)) {
transport.l = mnd_sprintf(&transport.s, 0, "tcp://[%s]:%u", hostname.s, port);
} else {
transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port);
}
}
DBG_INF_FMT("transport=%s", transport.s? transport.s:"OOM");
DBG_RETURN(transport);