Skip to content

Commit 6db12e7

Browse files
committed
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.
1 parent 21c2c07 commit 6db12e7

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ PHP NEWS
3030
- GD:
3131
. FIxed GH-19955 (imagefttext() memory leak). (David Carlier)
3232

33+
- MySQLnd:
34+
. Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress
35+
as parameter). (nielsdos)
36+
3337
- SimpleXML:
3438
. Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)).
3539
(nielsdos)

ext/mysqli/tests/bug67563.phpt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Fix bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress as parameter)
3+
--EXTENSIONS--
4+
mysqli
5+
--SKIPIF--
6+
<?php
7+
require_once 'connect.inc';
8+
9+
if ($host !== '127.0.0.1')
10+
die('skip local test');
11+
12+
if (@stream_socket_client('udp://[::1]:8888') === false)
13+
die('skip no IPv6 support 2');
14+
15+
if (!$link = @my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
16+
die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
17+
$host, $user, $db, $port, $socket));
18+
}
19+
?>
20+
--INI--
21+
max_execution_time=240
22+
--FILE--
23+
<?php
24+
require_once 'connect.inc';
25+
26+
$hosts = ['::1', "[::1]:$port"];
27+
28+
foreach ($hosts as $host) {
29+
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
30+
printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=%s dbname=%s, port=%s, socket=%s\n",
31+
$host, $user, $passwd, $db, $port, $socket);
32+
} else {
33+
$link->close();
34+
}
35+
}
36+
37+
print "done!";
38+
?>
39+
--EXPECT--
40+
done!

ext/mysqlnd/mysqlnd_connection.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,16 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn,
513513
}
514514
/* }}} */
515515

516+
/* ipv6 addresses have at least two colons, which is how we can differentiate between domain names and addresses */
517+
static bool mysqlnd_fast_is_ipv6_address(const char *s)
518+
{
519+
const char *first_colon = strchr(s, ':');
520+
if (!first_colon) {
521+
return false;
522+
}
523+
return strchr(first_colon + 1, ':') != NULL;
524+
}
525+
516526
/* {{{ mysqlnd_conn_data::get_scheme */
517527
static MYSQLND_STRING
518528
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_
542552
if (!port) {
543553
port = 3306;
544554
}
545-
transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port);
555+
556+
/* ipv6 addresses are in the format [address]:port */
557+
if (hostname.s[0] != '[' && mysqlnd_fast_is_ipv6_address(hostname.s)) {
558+
transport.l = mnd_sprintf(&transport.s, 0, "tcp://[%s]:%u", hostname.s, port);
559+
} else {
560+
transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port);
561+
}
546562
}
547563
DBG_INF_FMT("transport=%s", transport.s? transport.s:"OOM");
548564
DBG_RETURN(transport);

0 commit comments

Comments
 (0)