Skip to content

Commit

Permalink
Cleans up and simplifies logic to determine which type of IP addresse…
Browse files Browse the repository at this point in the history
…s (v4 or v6) to consider during name resolution. No longer inspect hosts interfaces to determine priority. Honors JVM properties defined for this purpose. Also updates TcpClientConnection to use whatever strategy specified by a user as part of a WebClient's configuration.
  • Loading branch information
spericas committed Jan 22, 2024
1 parent c11bce9 commit 4832656
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 53 deletions.
8 changes: 8 additions & 0 deletions webclient/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,14 +16,10 @@

package io.helidon.webclient.api;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import io.helidon.common.LazyValue;

import static java.lang.System.Logger.Level;

/**
* Heavily inspired by Netty.
*/
Expand All @@ -34,27 +30,22 @@ final class DefaultAddressLookupFinder {
/**
* {@code true} if IPv4 should be used even if the system supports both IPv4 and IPv6.
*/
private static final LazyValue<Boolean> IPV4_PREFERRED = LazyValue.create(() -> {
return Boolean.getBoolean("java.net.preferIPv4Stack");
});
private static final LazyValue<Boolean> IPV4_PREFERRED = LazyValue.create(() ->
Boolean.getBoolean("java.net.preferIPv4Stack"));

/**
* {@code true} if an IPv6 address should be preferred when a host has both an IPv4 address and an IPv6 address.
*/
private static final LazyValue<Boolean> IPV6_PREFERRED = LazyValue.create(() -> {
return Boolean.getBoolean("java.net.preferIPv6Addresses");
});
private static final LazyValue<Boolean> IPV6_PREFERRED = LazyValue.create(() ->
Boolean.getBoolean("java.net.preferIPv6Addresses"));

private static final LazyValue<DnsAddressLookup> DEFAULT_IP_VERSION = LazyValue.create(() -> {
if (IPV4_PREFERRED.get() || !anyInterfaceSupportsIpV6()) {
return DnsAddressLookup.IPV4;
} else {
if (IPV6_PREFERRED.get()) {
return DnsAddressLookup.IPV6_PREFERRED;
} else {
return DnsAddressLookup.IPV4_PREFERRED;
}
if (IPV4_PREFERRED.get() || !IPV6_PREFERRED.get()) {
LOGGER.log(Level.DEBUG, "Preferring IPv4 over IPv6 address resolution");
return DnsAddressLookup.IPV4_PREFERRED;
}
LOGGER.log(Level.DEBUG, "Preferring IPv6 over IPv4 address resolution");
return DnsAddressLookup.IPV6_PREFERRED;
});

private DefaultAddressLookupFinder() {
Expand All @@ -64,34 +55,4 @@ private DefaultAddressLookupFinder() {
static DnsAddressLookup defaultDnsAddressLookup() {
return DEFAULT_IP_VERSION.get();
}

/**
* Returns {@code true} if any {@link NetworkInterface} supports {@code IPv6}, {@code false} otherwise.
*/
private static boolean anyInterfaceSupportsIpV6() {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress inetAddress = addresses.nextElement();
if (inetAddress instanceof Inet6Address
&& !inetAddress.isAnyLocalAddress()
&& !inetAddress.isLoopbackAddress()
&& !inetAddress.isLinkLocalAddress()) {
return true;
}
}
}
} catch (SocketException ignore) {
if (LOGGER.isLoggable(System.Logger.Level.INFO)) {
LOGGER.log(System.Logger.Level.INFO,
"Unable to detect if any interface supports IPv6, assuming IPv4-only",
ignore);
}
}
return false;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,7 @@
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;
Expand Down Expand Up @@ -246,7 +247,16 @@ private String createChannelId(Socket socket) {
private InetSocketAddress inetSocketAddress() {
DnsResolver dnsResolver = connectionKey.dnsResolver();
if (dnsResolver.useDefaultJavaResolver()) {
return new InetSocketAddress(connectionKey.host(), connectionKey.port());
try {
InetAddress[] addresses = InetAddress.getAllByName(connectionKey.host());
addresses = connectionKey.dnsAddressLookup().filter(addresses);
if (addresses.length > 0) {
return new InetSocketAddress(addresses[0], connectionKey.port());
}
} catch (UnknownHostException e) {
// falls through
}
throw new IllegalArgumentException("Failed to get address from host: " + connectionKey.host());
} else {
InetAddress address = dnsResolver.resolveAddress(connectionKey.host(), connectionKey.dnsAddressLookup());
return new InetSocketAddress(address, connectionKey.port());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.webclient.api;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

class Ipv4LookupFinderTest {

/**
* Default is to prefer IPv4 addresses.
*/
@Test
void testIpv4Preference() {
DnsAddressLookup dnsAddressLookup = DefaultAddressLookupFinder.defaultDnsAddressLookup();
assertThat(dnsAddressLookup, is(DnsAddressLookup.IPV4_PREFERRED));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.webclient.api;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.nullValue;

class Ipv6LookupFinderTest {

/**
* If {@code java.net.preferIPv6Addresses} is set, use IPv6.
*/
@Test
void testIpv6Preference() {
assertThat(System.getProperty("java.net.preferIPv6Addresses"), is(nullValue()));
System.setProperty("java.net.preferIPv6Addresses", "true");
DnsAddressLookup dnsAddressLookup = DefaultAddressLookupFinder.defaultDnsAddressLookup();
assertThat(dnsAddressLookup, is(DnsAddressLookup.IPV6_PREFERRED));
}
}

0 comments on commit 4832656

Please sign in to comment.