From c0f5c3296c40c190e7f541c1ada20aef64d4bde9 Mon Sep 17 00:00:00 2001 From: Ilarion Nakonechnyy Date: Tue, 13 May 2025 01:12:47 +0300 Subject: [PATCH] Backport 9291b46bcfa76a596578eb50c29b9850e7020dea --- .../native/libdt_socket/socketTransport.c | 61 ++++++++++++--- test/jdk/com/sun/jdi/JdwpNetProps.java | 75 ++++++++++++++++--- 2 files changed, 117 insertions(+), 19 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c index 9d4e589c358..18844b85fc8 100644 --- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c @@ -727,11 +727,13 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, return err; } - // Try to find bind address of preferred address family first. - for (ai = addrInfo; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family == preferredAddressFamily) { - listenAddr = ai; - break; + // Try to find bind address of preferred address family first (if java.net.preferIPv6Addresses != "system"). + if (preferredAddressFamily != AF_UNSPEC) { + for (ai = addrInfo; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family == preferredAddressFamily) { + listenAddr = ai; + break; + } } } @@ -748,9 +750,9 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, // Binding to IN6ADDR_ANY allows to serve both IPv4 and IPv6 connections, // but binding to mapped INADDR_ANY (::ffff:0.0.0.0) allows to serve IPv4 // connections only. Make sure that IN6ADDR_ANY is preferred over - // mapped INADDR_ANY if preferredAddressFamily is AF_INET6 or not set. + // mapped INADDR_ANY if preferIPv4Stack is false. - if (preferredAddressFamily != AF_INET) { + if (!allowOnlyIPv4) { inet_pton(AF_INET6, "::ffff:0.0.0.0", &mappedAny); if (isEqualIPv6Addr(listenAddr, mappedAny)) { @@ -972,8 +974,10 @@ socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong a return err; } - /* 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest */ - for (pass = 0; pass < 2 && socketFD < 0; pass++) { + // 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest; + // if java.net.preferIPv6Addresses == "system", only 2nd pass is needed + pass = preferredAddressFamily != AF_UNSPEC ? 0 : 1; + for (; pass < 2 && socketFD < 0; pass++) { for (ai = addrInfo; ai != NULL; ai = ai->ai_next) { if ((pass == 0 && ai->ai_family == preferredAddressFamily) || (pass == 1 && ai->ai_family != preferredAddressFamily)) @@ -1310,6 +1314,43 @@ static int readBooleanSysProp(int *result, int trueValue, int falseValue, return JNI_OK; } +/* + * Reads java.net.preferIPv6Addresses system value, sets preferredAddressFamily to + * - AF_INET6 if the property is "true"; + * - AF_INET if the property is "false". + * - AF_UNSPEC if the property is "system". + * Doesn't change preferredAddressFamily if the property is not set or failed to read. + */ +static int readPreferIPv6Addresses(JNIEnv* jniEnv, + jclass sysClass, jmethodID getPropMethod, const char *propName) +{ + jstring value; + jstring name = (*jniEnv)->NewStringUTF(jniEnv, propName); + + if (name == NULL) { + return JNI_ERR; + } + value = (jstring)(*jniEnv)->CallStaticObjectMethod(jniEnv, sysClass, getPropMethod, name); + if ((*jniEnv)->ExceptionCheck(jniEnv)) { + return JNI_ERR; + } + if (value != NULL) { + const char *theValue = (*jniEnv)->GetStringUTFChars(jniEnv, value, NULL); + if (theValue == NULL) { + return JNI_ERR; + } + if (strcmp(theValue, "true") == 0) { + preferredAddressFamily = AF_INET6; + } else if (strcmp(theValue, "false") == 0) { + preferredAddressFamily = AF_INET; + } else if (strcmp(theValue, "system") == 0) { + preferredAddressFamily = AF_UNSPEC; + } + (*jniEnv)->ReleaseStringUTFChars(jniEnv, value, theValue); + } + return JNI_OK; +} + JNIEXPORT jint JNICALL jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr, jint version, jdwpTransportEnv** env) @@ -1367,7 +1408,7 @@ jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr, } readBooleanSysProp(&allowOnlyIPv4, 1, 0, jniEnv, sysClass, getPropMethod, "java.net.preferIPv4Stack"); - readBooleanSysProp(&preferredAddressFamily, AF_INET6, AF_INET, + readPreferIPv6Addresses( jniEnv, sysClass, getPropMethod, "java.net.preferIPv6Addresses"); } while (0); diff --git a/test/jdk/com/sun/jdi/JdwpNetProps.java b/test/jdk/com/sun/jdi/JdwpNetProps.java index 27769278b0c..af69c9ca3ad 100644 --- a/test/jdk/com/sun/jdi/JdwpNetProps.java +++ b/test/jdk/com/sun/jdi/JdwpNetProps.java @@ -36,15 +36,16 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; /* * @test - * @bug 8184770 + * @bug 8184770 8313804 * @summary Tests that JDWP agent honors jdk net properties * @library /test/lib * * @build HelloWorld JdwpNetProps - * @run main/othervm JdwpNetProps + * @run main/othervm -Djava.net.preferIPv6Addresses=system JdwpNetProps */ public class JdwpNetProps { @@ -60,33 +61,88 @@ public static void main(String[] args) throws Exception { } } + String preferIPv6Address = System.getProperty("java.net.preferIPv6Addresses"); + if (!Objects.equals(preferIPv6Address, "system")) { + throw new AssertionError( + "Expected -Djava.net.preferIPv6Address=system, was " + preferIPv6Address); + } + boolean systemPrefersIPv6 = addrs[0] instanceof Inet6Address; + if (ipv4Address != null) { new ListenTest("localhost", ipv4Address) .preferIPv4Stack(true) .run(TestResult.Success); + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(true) + .preferIPv6Addresses("true") + .run(TestResult.Success); + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(true) + .preferIPv6Addresses("system") + .run(TestResult.Success); new ListenTest("localhost", ipv4Address) .preferIPv4Stack(false) .run(TestResult.Success); if (ipv6Address != null) { - // - only IPv4, so connection prom IPv6 should fail + // - only IPv4, so connection from IPv6 should fail new ListenTest("localhost", ipv6Address) .preferIPv4Stack(true) - .preferIPv6Addresses(true) + .preferIPv6Addresses("true") + .run(TestResult.AttachFailed); + new ListenTest("localhost", ipv6Address) + .preferIPv4Stack(true) + .preferIPv6Addresses("system") .run(TestResult.AttachFailed); // - listen on IPv4 new ListenTest("localhost", ipv6Address) - .preferIPv6Addresses(false) + .preferIPv6Addresses("false") + .run(TestResult.AttachFailed); + // - listen on IPv4 (preferIPv6Addresses defaults to false) + new ListenTest("localhost", ipv6Address) .run(TestResult.AttachFailed); // - listen on IPv6 new ListenTest("localhost", ipv6Address) - .preferIPv6Addresses(true) + .preferIPv6Addresses("true") .run(TestResult.Success); + new ListenTest("localhost", ipv6Address) + .preferIPv6Addresses("system") + .run(systemPrefersIPv6 ? TestResult.Success : TestResult.AttachFailed); + // - listen on IPv6, connect from IPv4 + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(false) + .preferIPv6Addresses("true") + .run(TestResult.AttachFailed); + // - listen on system preference, connect from IPv4 + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(false) + .preferIPv6Addresses("system") + .run(systemPrefersIPv6 ? TestResult.AttachFailed : TestResult.Success); } } else { + if (!systemPrefersIPv6) { + throw new AssertionError("The system is IPv6-only, but systemPrefersIPv6 was unexpectedly false"); + } + // IPv6-only system - expected to fail on IPv4 address new ListenTest("localhost", ipv6Address) .preferIPv4Stack(true) .run(TestResult.ListenFailed); + new ListenTest("localhost", ipv6Address) + .preferIPv4Stack(true) + .preferIPv6Addresses("system") + .run(TestResult.ListenFailed); + new ListenTest("localhost", ipv6Address) + .preferIPv4Stack(true) + .preferIPv6Addresses("true") + .run(TestResult.ListenFailed); + new ListenTest("localhost", ipv6Address) + .run(TestResult.Success); + new ListenTest("localhost", ipv6Address) + .preferIPv6Addresses("system") + .run(TestResult.Success); + new ListenTest("localhost", ipv6Address) + .preferIPv6Addresses("true") + .run(TestResult.Success); } } @@ -100,7 +156,7 @@ private static class ListenTest { private final String listenAddress; private final InetAddress connectAddress; private Boolean preferIPv4Stack; - private Boolean preferIPv6Addresses; + private String preferIPv6Addresses; public ListenTest(String listenAddress, InetAddress connectAddress) { this.listenAddress = listenAddress; this.connectAddress = connectAddress; @@ -109,7 +165,7 @@ public ListenTest preferIPv4Stack(Boolean value) { preferIPv4Stack = value; return this; } - public ListenTest preferIPv6Addresses(Boolean value) { + public ListenTest preferIPv6Addresses(String value) { preferIPv6Addresses = value; return this; } @@ -120,7 +176,7 @@ public void run(TestResult expectedResult) throws Exception { options.add("-Djava.net.preferIPv4Stack=" + preferIPv4Stack.toString()); } if (preferIPv6Addresses != null) { - options.add("-Djava.net.preferIPv6Addresses=" + preferIPv6Addresses.toString()); + options.add("-Djava.net.preferIPv6Addresses=" + preferIPv6Addresses); } log("Starting listening debuggee at " + listenAddress + (expectedResult == TestResult.ListenFailed ? ": expected to fail" : "")); @@ -201,4 +257,5 @@ private static void log(Object o) { System.out.println(String.valueOf(o)); } + }