Java, Linux y IPv4 vs IPv6

Hoy he tenido una ración de problema extraño en un servidor. Por suerte no era un servidor de producción sino que era un servidor de red que tenia un servicio Tomcat secundario y casi de pruebas. El tema ha empezado al instalar una tercera tarjeta de red para gestionar una nueva conexión (a guifi.net aunque eso no es relevante). Al rato me doy cuenta que el servicio Tomcat no funciona.

Reviso los logs y tras mucho pelearme veo esto:

Jan 3, 2010 7:57:55 PM org.apache.catalina.core.StandardServer await SEVERE: StandardServer.await: create[8005]: java.net.SocketException: Invalid argument  
         at java.net.PlainSocketImpl.socketBind(Native Method)
         at java.net.PlainSocketImpl.bind(Unknown Source)
         at java.net.ServerSocket.bind(Unknown Source)
         at java.net.ServerSocket.(Unknown Source)
         at org.apache.catalina.core.StandardServer.await(StandardServer.java:363)
         at org.apache.catalina.startup.Catalina.await(Catalina.java:616)
         at org.apache.catalina.startup.Catalina.start(Catalina.java:576)
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
         at java.lang.reflect.Method.invoke(Unknown Source)
         at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295)
         at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433)

Tras mucha pelea, aumentar el verbose del servidor, busquedas por la red... nada. Al final me creo una pequeña aplicación Java para intentar encontrar el error...

import java.net.*;

public class Test {  
  public static void main (String[] args) throws Exception {
    InetAddress ip = InetAddress.getByName("127.0.0.1");
    System.out.println(ip);
    ServerSocket ss = new ServerSocket(2033, 1, ip);
    System.in.read();
  }
}

La sorpresa es que... falla!

sargue@bsg:~$ java Test  
/127.0.0.1
Exception in thread "main" java.net.SocketException: Invalid argument  
        at java.net.PlainSocketImpl.socketBind(Native Method)
        at java.net.PlainSocketImpl.bind(Unknown Source)
        at java.net.ServerSocket.bind(Unknown Source)
        at java.net.ServerSocket.(Unknown Source)
        at Test.main(Test.java:7)

Muy, muy extraño. Si en el código elimino la parte de la IP entonces sí funciona. Así que el problema debe estar en la IP. Cuando elimino la IP se me ocurre mirar donde la asigna y lo hace a una IPv6.

tcp6       0      0 :::2033                 :::*                    LISTEN      27945/java  

Así que eso me da la pista definitiva. Buscando más encuentro este post donde me entero de la opción de Java para forzar IPv4 lo cual resuelve la cuestión:

sargue@bsg:~$ java -Djava.net.preferIPv4Stack=true Test