Skip to content

8313804: JDWP support for -Djava.net.preferIPv6Addresses=system #3567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 51 additions & 10 deletions src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand All @@ -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)) {
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down
75 changes: 66 additions & 9 deletions test/jdk/com/sun/jdi/JdwpNetProps.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -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);
}
}

Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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" : ""));
Expand Down Expand Up @@ -201,4 +257,5 @@ private static void log(Object o) {
System.out.println(String.valueOf(o));
}


}