Bug 239890 - java/openjdk11: openjdk 11.0.4+11.2 JDBC connections fail with IPv6 addresses
Summary: java/openjdk11: openjdk 11.0.4+11.2 JDBC connections fail with IPv6 addresses
Status: New
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-java mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-08-15 21:27 UTC by Jonathan Chen
Modified: 2019-11-28 10:15 UTC (History)
2 users (show)

See Also:
bugzilla: maintainer-feedback? (java)


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Chen 2019-08-15 21:27:19 UTC
1.stormblade:jdbc-test,9:19am> cat J.java 
import java.sql.*;

public class J
{
        public static void
        main (
                String args[])
                throws Exception
        {
                String url = "jdbc:postgresql://[::1]/postgres?user=postgres";
                Connection conn = DriverManager.getConnection(url);
        }
}
1.stormblade:jdbc-test,9:20am> fetch https://jdbc.postgresql.org/download/postgresql-42.2.6.jar
postgresql-42.2.6.jar                                  823 kB  337 kBps    03s
1.stormblade:jdbc-test,9:20am> setenv JAVA_HOME /usr/local/openjdk8
1.stormblade:jdbc-test,9:20am> javac J.java 
1.stormblade:jdbc-test,9:21am> java -cp .:postgresql-42.2.6.jar J
1.stormblade:jdbc-test,9:21am> setenv JAVA_HOME /usr/local/openjdk11
1.stormblade:jdbc-test,9:21am> java -cp .:postgresql-42.2.6.jar J
Exception in thread "main" org.postgresql.util.PSQLException: The connection attempt failed.
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:292)
        at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
        at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195)
        at org.postgresql.Driver.makeConnection(Driver.java:458)
        at org.postgresql.Driver.connect(Driver.java:260)
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:251)
        at J.main(J.java:11)
Caused by: java.net.SocketException: Protocol family unavailable
        at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
        at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
        at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
        at java.base/java.net.Socket.connect(Socket.java:591)
        at org.postgresql.core.PGStream.<init>(PGStream.java:75)
        at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:91)
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:192)
        ... 7 more
1.stormblade:jdbc-test,9:24am> java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-2)
OpenJDK 64-Bit Server VM (build 11.0.4+11-2, mixed mode)
Comment 1 Greg Lewis freebsd_committer 2019-08-20 08:59:09 UTC
openjdk11 now prefers IPv4 addresses by default, i.e. the java.net.preferIPv4Stack property is now set to true by default.  Try setting it to false.

Without this a number of the internal jdk tests fail.
Comment 2 Jonathan Chen 2019-08-20 19:15:33 UTC
This appears to have worked:

7:08am> java -cp .:postgresql-42.2.6.jar -Djava.net.preferIPv4Stack=false J
7:08am> 

However, this small code snippet worked with the version before this, 11.0.4+11.1_2. Did the the preferIPv4Stack change with the latest version?

As this is a "preference", shouldn't the explicit use of an IPv6 address, ie [::1], indicate that the "preference" be ignored? Or did I misunderstand the semantics of java.net.preferIPv4Stack?
Comment 3 Greg Lewis freebsd_committer 2019-08-20 20:01:13 UTC
Yes, this was a change in the latest version.  Without it, tests which set socket options, for example, would consistently fail due to how the JVM assumes the OS handles dual mode sockets.  There is a better fix than this, but it requires substantial work.

I believe that based on how the socket code works at the moment, the handling on BSD means that "prefer" is a bit of a misnomer.  I can add a caveat to pkg-message regarding this since that might be helpful.
Comment 4 Jonathan Chen 2019-08-20 20:05:06 UTC
Note that according to:

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/doc-files/net-properties.html

java.net.preferIPv4Stack defaults to "false", so our pkg-message should state this is a BSD-ism.
Comment 5 Jonathan Chen 2019-08-20 20:34:15 UTC
Actually, it looks like the use of java.net.preferIPv4Stack=true is actually hiding a problem with OpenJDK11's IP address handling:

1.stormblade:jdbc-test,8:31am> ls    
J.java                 postgresql-42.2.6.jar    
1.stormblade:jdbc-test,8:31am> cat J.java     
import java.sql.*;  
  
public class J  
{  
        public static void  
        main (  
                String args[])  
                throws Exception  
        {  
                String url = "jdbc:postgresql://127.0.0.1/postgres?user=postgres";  
                Connection conn = DriverManager.getConnection(url);  
        }  
}  
1.stormblade:jdbc-test,8:31am> setenv JAVA_HOME /usr/local/openjdk8
1.stormblade:jdbc-test,8:31am> javac J.java    
1.stormblade:jdbc-test,8:31am> java -cp .:postgresql-42.2.6.jar -Djava.net.preferIPv4Stack=false J   
1.stormblade:jdbc-test,8:32am> setenv JAVA_HOME /usr/local/openjdk11    
1.stormblade:jdbc-test,8:32am> java -cp .:postgresql-42.2.6.jar -Djava.net.preferIPv4Stack=false J    
Exception in thread "main" org.postgresql.util.PSQLException: Connection to 127.0.0.1:5432 refused. Check that the hostname and port are correct and that the
 postmaster is accepting TCP/IP connections.  
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:280)  
        at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)  
        at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195)  
        at org.postgresql.Driver.makeConnection(Driver.java:458)  
        at org.postgresql.Driver.connect(Driver.java:260)  
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)  
        at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:251)  
        at J.main(J.java:11)  
Caused by: java.net.ConnectException: Invalid argument (connect failed)  
        at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)  
        at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)  
        at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)  
        at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)  
        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)  
        at java.base/java.net.Socket.connect(Socket.java:591)  
        at org.postgresql.core.PGStream.<init>(PGStream.java:75)  
        at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:91)  
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:192)  
        ... 7 more  
1.stormblade:jdbc-test,8:32am>
Comment 6 Greg Lewis freebsd_committer 2019-08-21 16:42:26 UTC
That's what I expect at the moment.  We'll either handle IPv4 addresses correctly (with the defaults) or we'll handle IPv6 addresses correctly (if you set java.net.preferIPv4Stack to false).  At the moment you can't do both.  Previously it did both brokenly.  I don't think there is an easy way to have both work correctly on BSD.

I can look into this code more deeply, but it'll probably take a while since I think there are some things that are higher priority right now.
Comment 7 DomF 2019-11-28 10:15:20 UTC
With respect to comment #5, the "invalid argument" mentioned in callstack:

Caused by: java.net.ConnectException: Invalid argument (connect failed)

Might be because when preferIPv4Stack is false, openjdk11 creates PF_INET6 domain sockets and subsequent connect()s try to use IPv4-mapped AF_INET6 addresses, as shown by this ktrace snippet:

  2979 java     CALL  socket(PF_INET6,0x1<SOCK_STREAM>,IPPROTO_IP)
  2979 java     RET   socket 34/0x22
  2979 java     CALL  fcntl(0x22,F_GETFL)
  2979 java     RET   fcntl 2
  2979 java     CALL  fcntl(0x22,F_SETFL,0x6<O_RDWR|O_NONBLOCK>)
  2979 java     RET   fcntl 0
  2979 java     CALL  connect(0x22,0x7fffdf663ce0,0x1c)
  2979 java     STRU  struct sockaddr { AF_INET6, [::ffff:151.101.16.133]:443 }
  2979 java     RET   connect -1 errno 22 Invalid argument

Even though openjdk11 possibly tries to turn off IPV6_V6ONLY on a per-socket basis[1] (although I'm not seeing that above) IPv4-mapped address use is still blocked by the sysctl net.inet6.ip6.v6only which is set to 1 by default.

If you set net.inet6.ip6.v6only to 0 then you might find your connection to 127.0.0.1 works with preferIPv4Stack set to false.

[1] Might not be the correct source, but:
https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/unix/native/libnet/PlainSocketImpl.c#L190