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)
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.
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?
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.
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.
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>
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.
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
Seems like this is the only way to have it work with both IPv4 and IPv6 at the same time. sudo sysctl net.inet6.ip6.v6only=0 It also seems the correct value anyways, but this is just me. AFAIK (but I'd like more comments on that) this parameter is only safe if this is added to pf.conf: table <v4mapped> const {0:0:0:0:0:FFFF::/96} block quick from <v4mapped> block quick to <v4mapped> Context about the security issue: https://lists.freebsd.org/pipermail/freebsd-net/2013-June/035858.html
I still wonder who is to blame here? The OS or bad C code in the JVM? When I try to create a listening socket with Python and the flags all works. May this really needs to be reported upstream with OpenJDK? I have played around a bit with that stuff while working on the libtcnative on FreeBSD (APR for Java binding for Tomcat).