Summary: | java/openjdk11: openjdk 11.0.4+11.2 JDBC connections fail with IPv6 addresses | ||
---|---|---|---|
Product: | Ports & Packages | Reporter: | Jonathan Chen <jonc> |
Component: | Individual Port(s) | Assignee: | freebsd-java (Nobody) <java> |
Status: | New --- | ||
Severity: | Affects Only Me | CC: | antonfb, freebsdbugs, glewis, lapo, michael.osipov, misc-freebsd-bugzilla, tom+fbsdbugzilla |
Priority: | --- | Flags: | bugzilla:
maintainer-feedback?
(java) |
Version: | Latest | ||
Hardware: | Any | ||
OS: | Any |
Description
Jonathan Chen
2019-08-15 21:27:19 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. 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). I'm not using this software but another java software in Freebsd with openjdk21. I couldn't bind to network addresses or connect to anything. Adding -Djava.net.preferIPv6Addresses=true -Djava.net.preferIPv4Stack=false to the cmdline fixed the issue. It seems that java.net.preferIPv4Stack defaults to true for the openjdk21 port too. Your issue is probably related. The same solution may apply here. |