MySQL e IPv6

Ahora que no se puede correr voy a aprovechar para hablar de otro de mis vicios, que no es otro que linux y para ello utilizo unas cuantas Raspberry Pi con sistema operativo Raspbian.

En su momento monté este blog utilizando dos raspberries. En una monté WordPress y en otra la BBDD MySQL. Se puede montar todo en una, pero lo hice para jugar un poco.

Una de las cosas que también me gusta es el tema de IPv6, esa gran revolución que iba a llegar y que se va posponiendo poco a poco. Las dos raspberry tienen dirección de IPv6 y además la dirección IPv6 se forma utilizando la dirección MAC. Estas direcciones IPv6 se llaman de enlace-local y tienen un alcance limitado, sería lo equivalente a las direcciones privadas de IPv4 del tipo 169.254.0.0/16. Son direcciones que se utilizan si no hay DHCP, pero son direcciones que se pueden utilizar.

Por ejemplo, una raspberry tiene la MAC dc:a6:32:1b:40:be y, por lo tanto, su dirección IPv6 es fe80::dea6:32ff:fe1b:40be/64. La otra rasp tiene la MAC b8:27:eb:35:25:f7 y, por lo tanto, la IPv6 es fe80::ba27:ebff:fe35:25f7/64. La gracia de este asunto es que independientemente de la IPv4 que le dé el DHCP ambas se pueden ver.

$ ping -c 4 fe80::ba27:ebff:fe35:25f7
 PING fe80::ba27:ebff:fe35:25f7(fe80::ba27:ebff:fe35:25f7) 56 data bytes
 64 bytes from fe80::ba27:ebff:fe35:25f7%eth0: icmp_seq=1 ttl=64 time=0.558 ms
 64 bytes from fe80::ba27:ebff:fe35:25f7%eth0: icmp_seq=2 ttl=64 time=0.502 ms
 64 bytes from fe80::ba27:ebff:fe35:25f7%eth0: icmp_seq=3 ttl=64 time=0.480 ms
 64 bytes from fe80::ba27:ebff:fe35:25f7%eth0: icmp_seq=4 ttl=64 time=0.478 ms
--- fe80::ba27:ebff:fe35:25f7 ping statistics ---
 4 packets transmitted, 4 received, 0% packet loss, time 94ms
 rtt min/avg/max/mdev = 0.478/0.504/0.558/0.039 ms

Desde la otra también hace ping

$ ping -c 4 fe80::dea6:32ff:fe1b:40be
 PING fe80::dea6:32ff:fe1b:40be(fe80::dea6:32ff:fe1b:40be) 56 data bytes
 64 bytes from fe80::dea6:32ff:fe1b:40be%eth0: icmp_seq=1 ttl=64 time=0.501 ms
 64 bytes from fe80::dea6:32ff:fe1b:40be%eth0: icmp_seq=2 ttl=64 time=0.474 ms
 64 bytes from fe80::dea6:32ff:fe1b:40be%eth0: icmp_seq=3 ttl=64 time=0.485 ms
 64 bytes from fe80::dea6:32ff:fe1b:40be%eth0: icmp_seq=4 ttl=64 time=0.447 ms 
--- fe80::dea6:32ff:fe1b:40be ping statistics ---
 4 packets transmitted, 4 received, 0% packet loss, time 115ms
 rtt min/avg/max/mdev = 0.447/0.476/0.501/0.033 ms

También se puede utilizar la dirección IPv6 para entrar por SSH

$ ssh usuario@fe80::ba27:ebff:fe35:25f7

Linux raspberri_bbdd 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l
 The programs included with the Debian GNU/Linux system are free software;
 the exact distribution terms for each program are described in the
 individual files in /usr/share/doc/*/copyright.
 Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 permitted by applicable law.
 Last login: Sun Mar 15 11:11:05 2020 from fe80::dea6:32ff:fe1b:40be%eth0

Pues bien, se puede hacer ping, se puede entrar por SSH, pero una de las cosas que me estaba fallando era utilizar el cliente MySQL para acceder a la base de datos. Configuré el servidor como dice la documentación y traté de entrar:

mysql -hfe80::ba27:ebff:feff:a84a -uusuario -pcontrasenia bbdd
 ERROR 2002 (HY000): Can't connect to MySQL server on 'fe80::ba27:ebff:feff:a84a' (22)

Comprobé si desde la propia máquina se podía entrar utilizando la dirección de loopback de IPv6 (::1) y vi que funcionaba:

$ mysql -h::1 -uusuario -pcontrasenia bbdd
 Reading table information for completion of table and column names
 You can turn off this feature to get a quicker startup with -A
 Welcome to the MariaDB monitor.  Commands end with ; or \g.
 Your MariaDB connection id is 10310
 Server version: 10.3.22-MariaDB-0+deb10u1 Raspbian 10
 Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 MariaDB [bbdd]>

Lo más gracioso es que probando desde un «linux integrado» dentro de Windows 10 ¡sí funcionaba! Eso sí me descolocó del todo. Que funcione en un linux cutre y no funcione en uno de verdad, me chafó del todo. También probé desde la línea de comandos de un Mac y tampoco funcionó.

$ mysql -hfe80::ba27:ebff:fe35:25f7 -uusuario -pcontrasenia bbdd  Reading table information for completion of table and column names  You can turn off this feature to get a quicker startup with -A  Welcome to the MariaDB monitor.  Commands end with ; or \g.  Your MariaDB connection id is 10322  Server version: 10.3.22-MariaDB-0+deb10u1 Raspbian 10  Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.  Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.  
MariaDB [bbdd]>

La verdad es que estuve dando muchas vueltas y me he comido mucho la cabeza hasta que al final he conseguido dar con ello. Todo viene porque en IPv6 hay que especificar la interfaz por donde sale el tráfico para llegar al destino. En mi caso, la interfaz es eth0 y, por lo tanto, hay que añadir el sufijo %eth0 a la dirección IPv6. La cosa quedaría:

$ mysql -hfe80::ba27:ebff:feff:a84a%eth0 -uusuario -pcontrasenia bbdd
 Reading table information for completion of table and column names
 You can turn off this feature to get a quicker startup with -A
 Welcome to the MariaDB monitor.  Commands end with ; or \g.
 Your MariaDB connection id is 112
 Server version: 10.3.22-MariaDB-0+deb10u1 Raspbian 10
 Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 MariaDB [bbdd]>

Normalmente este tipo de problemas suele ocurrir por no leer la documentación, pero en este caso no es así porque la documentación es incorrecta. En este enlace habla del asunto y no dice nada de la interfaz:

También se puede desde PHP conectar usando IPv6, que era el motivo principal por el que empecé con todo este asunto. En este caso además de añadir la interfaz hay que meterlo todo entre llaves cuadradas []. La cosa quedaría algo así:

<?php
# Se definen unas variables
define("DATABASE","bbdd");
define("PASSWD","contrasenia");
define("USER","usuario");
define("SERVER",'[fe80::ba27:ebff:fe35:25f7%eth0]');
$mysqli =  mysqli_connect(SERVER, USER, PASSWD, DATABASE);     
if ($mysqli->connect_error) {             
    die('Error de conexión: ' . $mysqli->connect_error);     
}     
echo "Conectado  satisfactoriamente\n";
?>