Skip to content

Commit

Permalink
Network: Allow to listen on virtual interfaces.
Browse files Browse the repository at this point in the history
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 elastic#19537 because it causes tests
to fail when interfaces are down. The test has been modified
to take this into account now.

Closes elastic#17473
Closes elastic#19568
Relates elastic#19537
  • Loading branch information
daschl authored and spinscale committed Sep 13, 2016
1 parent 262a5ee commit 041e811
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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> 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<InetAddress> list = Collections.list(intf.getInetAddresses());
List<InetAddress> list = Collections.list(networkInterface.get().getInetAddresses());
if (list.isEmpty()) {
throw new IllegalArgumentException("Interface '" + name + "' has no internet addresses");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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"));
}
}

0 comments on commit 041e811

Please sign in to comment.