From 9ee6624fd1ea8036704cc0d709a7d4f5aa0b863d Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Thu, 21 Jul 2016 14:54:55 +0200 Subject: [PATCH] Network: Allow to listen on virtual interfaces. Previously when trying to listen on virtual interfaces during bootstrap the application would stop working - the interface couldn't be found by the NetworkUtils class. The NetworkUtils utilize the underlying JDK NetworkInterface class which, when asked to lookup by name only takes physical interfaces into account, failing at virtual (or subinterfaces) ones (returning null). Note that when interating over all interfaces, both physical and virtual ones are taken into account. This changeset asks for all known interfaces, iterates over them and matches on the given name as part of the loop, allowing it to catch both physical and virtual interfaces. As a result, elasticsearch can now also serve on virtual interfaces. A test case has been added which makes sure that all iterable interfaces can be found by their respective name. Note that this PR is a second iteration over the previously merged but later reverted #19537 because it causes tests to fail when interfaces are down. The test has been modified to take this into account now. Closes #17473 Closes #19568 Relates #19537 --- .../common/network/NetworkUtils.java | 10 ++++--- .../common/network/NetworkUtilsTests.java | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java b/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java index 8652d4c5c0521..9e06c39b83e03 100644 --- a/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java +++ b/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; /** * Utilities for network interfaces / addresses binding and publishing. @@ -227,14 +228,15 @@ static InetAddress[] getAllAddresses() throws SocketException { /** Returns addresses for the given interface (it must be marked up) */ static InetAddress[] getAddressesForInterface(String name) throws SocketException { - NetworkInterface intf = NetworkInterface.getByName(name); - if (intf == null) { + Optional networkInterface = getInterfaces().stream().filter((netIf) -> name.equals(netIf.getName())).findFirst(); + + if (networkInterface.isPresent() == false) { throw new IllegalArgumentException("No interface named '" + name + "' found, got " + getInterfaces()); } - if (!intf.isUp()) { + if (!networkInterface.get().isUp()) { throw new IllegalArgumentException("Interface '" + name + "' is not up and running"); } - List list = Collections.list(intf.getInetAddresses()); + List list = Collections.list(networkInterface.get().getInetAddresses()); if (list.isEmpty()) { throw new IllegalArgumentException("Interface '" + name + "' has no internet addresses"); } diff --git a/core/src/test/java/org/elasticsearch/common/network/NetworkUtilsTests.java b/core/src/test/java/org/elasticsearch/common/network/NetworkUtilsTests.java index e5b95f258a3e2..85a7472416166 100644 --- a/core/src/test/java/org/elasticsearch/common/network/NetworkUtilsTests.java +++ b/core/src/test/java/org/elasticsearch/common/network/NetworkUtilsTests.java @@ -22,6 +22,10 @@ import org.elasticsearch.test.ESTestCase; import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Collections; + +import static org.hamcrest.Matchers.containsString; /** * Tests for network utils. Please avoid using any methods that cause DNS lookups! @@ -74,4 +78,30 @@ public void testFilter() throws Exception { assertArrayEquals(new InetAddress[] { InetAddress.getByName("127.0.0.1") }, NetworkUtils.filterIPV4(addresses)); assertArrayEquals(new InetAddress[] { InetAddress.getByName("::1") }, NetworkUtils.filterIPV6(addresses)); } + + /** + * Test that selecting by name is possible and properly matches the addresses on all interfaces and virtual + * interfaces. + * + * Note that to avoid that this test fails when interfaces are down or they do not have addresses assigned to them, + * they are ignored. + */ + public void testAddressInterfaceLookup() throws Exception { + for (NetworkInterface netIf : NetworkUtils.getInterfaces()) { + if (!netIf.isUp() || Collections.list(netIf.getInetAddresses()).isEmpty()) { + continue; + } + + String name = netIf.getName(); + InetAddress[] expectedAddresses = Collections.list(netIf.getInetAddresses()).toArray(new InetAddress[0]); + InetAddress[] foundAddresses = NetworkUtils.getAddressesForInterface(name); + assertArrayEquals(expectedAddresses, foundAddresses); + } + } + + public void testNonExistingInterface() throws Exception { + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> NetworkUtils.getAddressesForInterface("non-existing")); + assertThat(exception.getMessage(), containsString("No interface named 'non-existing' found")); + } }