diff --git a/core/src/main/java/org/elasticsearch/common/network/NetworkService.java b/core/src/main/java/org/elasticsearch/common/network/NetworkService.java index 8eff70e7bd8f5..c42e95f6bdb82 100644 --- a/core/src/main/java/org/elasticsearch/common/network/NetworkService.java +++ b/core/src/main/java/org/elasticsearch/common/network/NetworkService.java @@ -28,6 +28,9 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; @@ -91,13 +94,21 @@ public void addCustomNameResolver(CustomNameResolver customNameResolver) { customNameResolvers.add(customNameResolver); } - public InetAddress[] resolveBindHostAddress(String bindHost) throws IOException { + /** + * Resolves {@code bindHosts} to a list of internet addresses. The list will + * not contain duplicate addresses. + * @param bindHosts list of hosts to bind to. this may contain special pseudo-hostnames + * such as _local_ (see the documentation). if it is null, it will be populated + * based on global default settings. + * @return unique set of internet addresses + */ + public InetAddress[] resolveBindHostAddresses(String bindHosts[]) throws IOException { // first check settings - if (bindHost == null) { - bindHost = settings.get(GLOBAL_NETWORK_BINDHOST_SETTING, settings.get(GLOBAL_NETWORK_HOST_SETTING)); + if (bindHosts == null) { + bindHosts = settings.getAsArray(GLOBAL_NETWORK_BINDHOST_SETTING, settings.getAsArray(GLOBAL_NETWORK_HOST_SETTING, null)); } // next check any registered custom resolvers - if (bindHost == null) { + if (bindHosts == null) { for (CustomNameResolver customNameResolver : customNameResolvers) { InetAddress addresses[] = customNameResolver.resolveDefault(); if (addresses != null) { @@ -106,31 +117,44 @@ public InetAddress[] resolveBindHostAddress(String bindHost) throws IOException } } // finally, fill with our default - if (bindHost == null) { - bindHost = DEFAULT_NETWORK_HOST; + if (bindHosts == null) { + bindHosts = new String[] { DEFAULT_NETWORK_HOST }; } - InetAddress addresses[] = resolveInetAddress(bindHost); + InetAddress addresses[] = resolveInetAddresses(bindHosts); // try to deal with some (mis)configuration - if (addresses != null) { - for (InetAddress address : addresses) { - // check if its multicast: flat out mistake - if (address.isMulticastAddress()) { - throw new IllegalArgumentException("bind address: {" + NetworkAddress.format(address) + "} is invalid: multicast address"); - } + for (InetAddress address : addresses) { + // check if its multicast: flat out mistake + if (address.isMulticastAddress()) { + throw new IllegalArgumentException("bind address: {" + NetworkAddress.format(address) + "} is invalid: multicast address"); + } + // check if its a wildcard address: this is only ok if its the only address! + if (address.isAnyLocalAddress() && addresses.length > 1) { + throw new IllegalArgumentException("bind address: {" + NetworkAddress.format(address) + "} is wildcard, but multiple addresses specified: this makes no sense"); } } return addresses; } + /** + * Resolves {@code publishHosts} to a single publish address. The fact that it returns + * only one address is just a current limitation. + *

+ * If {@code publishHosts} resolves to more than one address, then one is selected with magic, + * and the user is warned (they can always just be more specific). + * @param publishHosts list of hosts to publish as. this may contain special pseudo-hostnames + * such as _local_ (see the documentation). if it is null, it will be populated + * based on global default settings. + * @return single internet address + */ // TODO: needs to be InetAddress[] - public InetAddress resolvePublishHostAddress(String publishHost) throws IOException { + public InetAddress resolvePublishHostAddresses(String publishHosts[]) throws IOException { // first check settings - if (publishHost == null) { - publishHost = settings.get(GLOBAL_NETWORK_PUBLISHHOST_SETTING, settings.get(GLOBAL_NETWORK_HOST_SETTING)); + if (publishHosts == null) { + publishHosts = settings.getAsArray(GLOBAL_NETWORK_PUBLISHHOST_SETTING, settings.getAsArray(GLOBAL_NETWORK_HOST_SETTING, null)); } // next check any registered custom resolvers - if (publishHost == null) { + if (publishHosts == null) { for (CustomNameResolver customNameResolver : customNameResolvers) { InetAddress addresses[] = customNameResolver.resolveDefault(); if (addresses != null) { @@ -139,30 +163,61 @@ public InetAddress resolvePublishHostAddress(String publishHost) throws IOExcept } } // finally, fill with our default - if (publishHost == null) { - publishHost = DEFAULT_NETWORK_HOST; + if (publishHosts == null) { + publishHosts = new String[] { DEFAULT_NETWORK_HOST }; } + InetAddress addresses[] = resolveInetAddresses(publishHosts); // TODO: allow publishing multiple addresses - InetAddress address = resolveInetAddress(publishHost)[0]; + // for now... the hack begins - // try to deal with some (mis)configuration - if (address != null) { + // 1. single wildcard address, probably set by network.host + if (addresses.length == 1 && addresses[0].isAnyLocalAddress()) { + InetAddress old = addresses[0]; + addresses = resolveInetAddresses(new String[] { "_non_loopback_" }); + logger.warn("publish address: {{}} is a wildcard address, falling back to _non_loopback_", + NetworkAddress.format(old)); + } + + // 2. try to deal with some (mis)configuration + for (InetAddress address : addresses) { // check if its multicast: flat out mistake if (address.isMulticastAddress()) { throw new IllegalArgumentException("publish address: {" + NetworkAddress.format(address) + "} is invalid: multicast address"); } - // wildcard address, probably set by network.host + // check if its a wildcard address: this is only ok if its the only address! + // (if it was a single wildcard address, it was replaced by step 1 above) if (address.isAnyLocalAddress()) { - InetAddress old = address; - address = NetworkUtils.getFirstNonLoopbackAddresses()[0]; - logger.warn("publish address: {{}} is a wildcard address, falling back to first non-loopback: {{}}", - NetworkAddress.format(old), NetworkAddress.format(address)); + throw new IllegalArgumentException("publish address: {" + NetworkAddress.format(address) + "} is wildcard, but multiple addresses specified: this makes no sense"); } } - return address; + + // 3. warn user if we end out with multiple publish addresses + if (addresses.length > 1) { + List sorted = new ArrayList<>(Arrays.asList(addresses)); + NetworkUtils.sortAddresses(sorted); + addresses = new InetAddress[] { sorted.get(0) }; + logger.warn("publish host: {} resolves to multiple addresses, auto-selecting {{}} as single publish address", + Arrays.toString(publishHosts), NetworkAddress.format(addresses[0])); + } + return addresses[0]; + } + + /** resolves (and deduplicates) host specification */ + private InetAddress[] resolveInetAddresses(String hosts[]) throws UnknownHostException, IOException { + if (hosts.length == 0) { + throw new IllegalArgumentException("empty host specification"); + } + // deduplicate, in case of resolver misconfiguration + // stuff like https://bugzilla.redhat.com/show_bug.cgi?id=496300 + HashSet set = new HashSet<>(); + for (String host : hosts) { + set.addAll(Arrays.asList(resolveInternal(host))); + } + return set.toArray(new InetAddress[set.size()]); } - private InetAddress[] resolveInetAddress(String host) throws UnknownHostException, IOException { + /** resolves a single host specification */ + private InetAddress[] resolveInternal(String host) throws UnknownHostException, IOException { if ((host.startsWith("#") && host.endsWith("#")) || (host.startsWith("_") && host.endsWith("_"))) { host = host.substring(1, host.length() - 1); // allow custom resolvers to have special names @@ -198,6 +253,6 @@ private InetAddress[] resolveInetAddress(String host) throws UnknownHostExceptio } } } - return NetworkUtils.getAllByName(host); + return InetAddress.getAllByName(host); } } 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 62bc91cfb85dd..371469492b10d 100644 --- a/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java +++ b/core/src/main/java/org/elasticsearch/common/network/NetworkUtils.java @@ -27,12 +27,10 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.List; /** @@ -109,7 +107,8 @@ static int sortKey(InetAddress address, boolean prefer_v6) { * @deprecated remove this when multihoming is really correct */ @Deprecated - static void sortAddresses(List list) { + // only public because of silly multicast + public static void sortAddresses(List list) { Collections.sort(list, new Comparator() { @Override public int compare(InetAddress left, InetAddress right) { @@ -161,7 +160,6 @@ static InetAddress[] getLoopbackAddresses() throws SocketException { if (list.isEmpty()) { throw new IllegalArgumentException("No up-and-running loopback interfaces found, got " + getInterfaces()); } - sortAddresses(list); return list.toArray(new InetAddress[list.size()]); } @@ -177,7 +175,6 @@ static InetAddress[] getFirstNonLoopbackAddresses() throws SocketException { if (list.isEmpty()) { throw new IllegalArgumentException("No up-and-running non-loopback interfaces found, got " + getInterfaces()); } - sortAddresses(list); return list.toArray(new InetAddress[list.size()]); } @@ -194,20 +191,9 @@ static InetAddress[] getAddressesForInterface(String name) throws SocketExceptio if (list.isEmpty()) { throw new IllegalArgumentException("Interface '" + name + "' has no internet addresses"); } - sortAddresses(list); return list.toArray(new InetAddress[list.size()]); } - /** Returns addresses for the given host, sorted by order of preference */ - static InetAddress[] getAllByName(String host) throws UnknownHostException { - InetAddress addresses[] = InetAddress.getAllByName(host); - // deduplicate, in case of resolver misconfiguration - // stuff like https://bugzilla.redhat.com/show_bug.cgi?id=496300 - List unique = new ArrayList<>(new HashSet<>(Arrays.asList(addresses))); - sortAddresses(unique); - return unique.toArray(new InetAddress[unique.size()]); - } - /** Returns only the IPV4 addresses in {@code addresses} */ static InetAddress[] filterIPV4(InetAddress addresses[]) { List list = new ArrayList<>(); diff --git a/core/src/main/java/org/elasticsearch/http/netty/NettyHttpServerTransport.java b/core/src/main/java/org/elasticsearch/http/netty/NettyHttpServerTransport.java index a794f52dfaffe..3dbe3bf0df69a 100644 --- a/core/src/main/java/org/elasticsearch/http/netty/NettyHttpServerTransport.java +++ b/core/src/main/java/org/elasticsearch/http/netty/NettyHttpServerTransport.java @@ -50,6 +50,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; @@ -105,9 +106,9 @@ public class NettyHttpServerTransport extends AbstractLifecycleComponent boundAddresses = new ArrayList<>(hostAddresses.length); @@ -262,7 +263,7 @@ protected void doStart() { publishPort = boundAddress.getPort(); } try { - publishAddress = new InetSocketAddress(networkService.resolvePublishHostAddress(publishHost), publishPort); + publishAddress = new InetSocketAddress(networkService.resolvePublishHostAddresses(publishHosts), publishPort); } catch (Exception e) { throw new BindTransportException("Failed to resolve publish address", e); } diff --git a/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java b/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java index 5cf9ed31d32f4..f4319bb2cfd9a 100644 --- a/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java +++ b/core/src/main/java/org/elasticsearch/transport/netty/NettyTransport.java @@ -343,9 +343,9 @@ public Map profileBoundAddresses() { return ImmutableMap.copyOf(profileBoundAddresses); } - private InetSocketAddress createPublishAddress(String publishHost, int publishPort) { + private InetSocketAddress createPublishAddress(String publishHosts[], int publishPort) { try { - return new InetSocketAddress(networkService.resolvePublishHostAddress(publishHost), publishPort); + return new InetSocketAddress(networkService.resolvePublishHostAddresses(publishHosts), publishPort); } catch (Exception e) { throw new BindTransportException("Failed to resolve publish address", e); } @@ -436,11 +436,11 @@ private Settings createFallbackSettings() { private void bindServerBootstrap(final String name, final Settings settings) { // Bind and start to accept incoming connections. InetAddress hostAddresses[]; - String bindHost = settings.get("bind_host"); + String bindHosts[] = settings.getAsArray("bind_host", null); try { - hostAddresses = networkService.resolveBindHostAddress(bindHost); + hostAddresses = networkService.resolveBindHostAddresses(bindHosts); } catch (IOException e) { - throw new BindTransportException("Failed to resolve host [" + bindHost + "]", e); + throw new BindTransportException("Failed to resolve host " + Arrays.toString(bindHosts) + "", e); } if (logger.isDebugEnabled()) { String[] addresses = new String[hostAddresses.length]; @@ -493,8 +493,8 @@ public boolean onPortNumber(int portNumber) { if (boundTransportAddress == null) { // no address is bound, so lets create one with the publish address information from the settings or the bound address as a fallback int publishPort = profileSettings.getAsInt("publish_port", boundAddress.getPort()); - String publishHost = profileSettings.get("publish_host", boundAddress.getHostString()); - InetSocketAddress publishAddress = createPublishAddress(publishHost, publishPort); + String publishHosts[] = profileSettings.getAsArray("publish_host", new String[] { boundAddress.getHostString() }); + InetSocketAddress publishAddress = createPublishAddress(publishHosts, publishPort); profileBoundAddresses.put(name, new BoundTransportAddress(new TransportAddress[]{new InetSocketTransportAddress(boundAddress)}, new InetSocketTransportAddress(publishAddress))); } else { // TODO: support real multihoming with publishing. Today we update the bound addresses so only the prioritized address is published @@ -511,8 +511,8 @@ public boolean onPortNumber(int portNumber) { // these calls are different from the profile ones due to the way the settings for a profile are created. If we want to merge the code for the default profile and // other profiles together, we need to change how the profileSettings are built for the default profile... int publishPort = settings.getAsInt("transport.netty.publish_port", settings.getAsInt("transport.publish_port", boundAddress.getPort())); - String publishHost = settings.get("transport.netty.publish_host", settings.get("transport.publish_host", settings.get("transport.host"))); - InetSocketAddress publishAddress = createPublishAddress(publishHost, publishPort); + String publishHosts[] = settings.getAsArray("transport.netty.publish_host", settings.getAsArray("transport.publish_host", settings.getAsArray("transport.host", null))); + InetSocketAddress publishAddress = createPublishAddress(publishHosts, publishPort); this.boundAddress = new BoundTransportAddress(new TransportAddress[]{new InetSocketTransportAddress(boundAddress)}, new InetSocketTransportAddress(publishAddress)); } else { // the default profile is already bound to one address and has the publish address, copy the existing bound addresses as is and append the new address. diff --git a/core/src/test/java/org/elasticsearch/common/network/NetworkServiceTests.java b/core/src/test/java/org/elasticsearch/common/network/NetworkServiceTests.java index 0a772907a8ca9..7be9547827b2d 100644 --- a/core/src/test/java/org/elasticsearch/common/network/NetworkServiceTests.java +++ b/core/src/test/java/org/elasticsearch/common/network/NetworkServiceTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.test.ESTestCase; import java.net.InetAddress; +import java.util.Arrays; /** * Tests for network service... try to keep them safe depending upon configuration @@ -36,7 +37,7 @@ public class NetworkServiceTests extends ESTestCase { public void testBindMulticastV4() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); try { - service.resolveBindHostAddress("239.1.1.1"); + service.resolveBindHostAddresses(new String[] { "239.1.1.1" }); fail("should have hit exception"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("invalid: multicast")); @@ -49,7 +50,7 @@ public void testBindMulticastV4() throws Exception { public void testBindMulticastV6() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); try { - service.resolveBindHostAddress("FF08::108"); + service.resolveBindHostAddresses(new String[] { "FF08::108" }); fail("should have hit exception"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("invalid: multicast")); @@ -62,7 +63,7 @@ public void testBindMulticastV6() throws Exception { public void testPublishMulticastV4() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); try { - service.resolvePublishHostAddress("239.1.1.1"); + service.resolvePublishHostAddresses(new String[] { "239.1.1.1" }); fail("should have hit exception"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("invalid: multicast")); @@ -75,7 +76,7 @@ public void testPublishMulticastV4() throws Exception { public void testPublishMulticastV6() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); try { - service.resolvePublishHostAddress("FF08::108"); + service.resolvePublishHostAddresses(new String[] { "FF08::108" }); fail("should have hit exception"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("invalid: multicast")); @@ -87,7 +88,7 @@ public void testPublishMulticastV6() throws Exception { */ public void testBindAnyLocalV4() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); - assertEquals(InetAddress.getByName("0.0.0.0"), service.resolveBindHostAddress("0.0.0.0")[0]); + assertEquals(InetAddress.getByName("0.0.0.0"), service.resolveBindHostAddresses(new String[] { "0.0.0.0" })[0]); } /** @@ -95,36 +96,38 @@ public void testBindAnyLocalV4() throws Exception { */ public void testBindAnyLocalV6() throws Exception { NetworkService service = new NetworkService(Settings.EMPTY); - assertEquals(InetAddress.getByName("::"), service.resolveBindHostAddress("::")[0]); + assertEquals(InetAddress.getByName("::"), service.resolveBindHostAddresses(new String[] { "::" })[0]); } /** * ensure specifying wildcard ipv4 address selects reasonable publish address */ public void testPublishAnyLocalV4() throws Exception { - InetAddress expected = null; + InetAddress expected[] = null; try { - expected = NetworkUtils.getFirstNonLoopbackAddresses()[0]; + expected = NetworkUtils.getFirstNonLoopbackAddresses(); } catch (Exception e) { assumeNoException("test requires up-and-running non-loopback address", e); } + NetworkUtils.sortAddresses(Arrays.asList(expected)); NetworkService service = new NetworkService(Settings.EMPTY); - assertEquals(expected, service.resolvePublishHostAddress("0.0.0.0")); + assertEquals(expected[0], service.resolvePublishHostAddresses(new String[] { "0.0.0.0" })); } /** * ensure specifying wildcard ipv6 address selects reasonable publish address */ public void testPublishAnyLocalV6() throws Exception { - InetAddress expected = null; + InetAddress expected[] = null; try { - expected = NetworkUtils.getFirstNonLoopbackAddresses()[0]; + expected = NetworkUtils.getFirstNonLoopbackAddresses(); } catch (Exception e) { assumeNoException("test requires up-and-running non-loopback address", e); } + NetworkUtils.sortAddresses(Arrays.asList(expected)); NetworkService service = new NetworkService(Settings.EMPTY); - assertEquals(expected, service.resolvePublishHostAddress("::")); + assertEquals(expected[0], service.resolvePublishHostAddresses(new String[] { "::" })); } } diff --git a/docs/reference/modules/network.asciidoc b/docs/reference/modules/network.asciidoc index dc6aca718cdcb..a44b895ac4474 100644 --- a/docs/reference/modules/network.asciidoc +++ b/docs/reference/modules/network.asciidoc @@ -22,8 +22,8 @@ ordinary addresses are preferred to site-local or link-local addresses. The `network.host` setting is a simple setting to automatically set both `network.bind_host` and `network.publish_host` to the same host value. -Both settings allows to be configured with either explicit host address -or host name. The settings also accept logical setting values explained +Both settings allows to be configured with either explicit host address(es) +or host name(s). The settings also accept logical setting value(s) explained in the following table: [cols="<,<",options="header",] diff --git a/plugins/cloud-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java b/plugins/cloud-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java index 8feb9b8697cc7..476773dcc7316 100644 --- a/plugins/cloud-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java +++ b/plugins/cloud-gce/src/main/java/org/elasticsearch/discovery/gce/GceUnicastHostsProvider.java @@ -110,7 +110,7 @@ public List buildDynamicNodes() { cachedDiscoNodes = new ArrayList<>(); String ipAddress = null; try { - InetAddress inetAddress = networkService.resolvePublishHostAddress(null); + InetAddress inetAddress = networkService.resolvePublishHostAddresses(null); if (inetAddress != null) { ipAddress = NetworkAddress.formatAddress(inetAddress); } diff --git a/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java b/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java index b2e6821e30d27..9f58b0bbb18d7 100644 --- a/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java +++ b/plugins/discovery-azure/src/main/java/org/elasticsearch/discovery/azure/AzureUnicastHostsProvider.java @@ -177,7 +177,7 @@ public List buildDynamicNodes() { InetAddress ipAddress = null; try { - ipAddress = networkService.resolvePublishHostAddress(null); + ipAddress = networkService.resolvePublishHostAddresses(null); logger.trace("ip of current node: [{}]", ipAddress); } catch (IOException e) { // We can't find the publish host address... Hmmm. Too bad :-( diff --git a/plugins/discovery-multicast/pom.xml b/plugins/discovery-multicast/pom.xml index eaa1e112f3413..5ffa5d0c5d6d5 100644 --- a/plugins/discovery-multicast/pom.xml +++ b/plugins/discovery-multicast/pom.xml @@ -19,6 +19,7 @@ 1 discovery_multicast false + -Xlint:-deprecation diff --git a/plugins/discovery-multicast/src/main/java/org/elasticsearch/plugin/discovery/multicast/MulticastZenPing.java b/plugins/discovery-multicast/src/main/java/org/elasticsearch/plugin/discovery/multicast/MulticastZenPing.java index 5b61787cdebd0..d21750fb6f5ae 100644 --- a/plugins/discovery-multicast/src/main/java/org/elasticsearch/plugin/discovery/multicast/MulticastZenPing.java +++ b/plugins/discovery-multicast/src/main/java/org/elasticsearch/plugin/discovery/multicast/MulticastZenPing.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.network.NetworkService; +import org.elasticsearch.common.network.NetworkUtils; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AbstractRunnable; @@ -47,7 +48,10 @@ import org.elasticsearch.transport.*; import java.io.IOException; +import java.net.InetAddress; import java.net.SocketAddress; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @@ -130,11 +134,14 @@ protected void doStart() { boolean shared = settings.getAsBoolean("discovery.zen.ping.multicast.shared", Constants.MAC_OS_X); // OSX does not correctly send multicasts FROM the right interface boolean deferToInterface = settings.getAsBoolean("discovery.zen.ping.multicast.defer_group_to_set_interface", Constants.MAC_OS_X); + // don't use publish address, the use case for that is e.g. a firewall or proxy and + // may not even be bound to an interface on this machine! use the first bound address. + List addresses = Arrays.asList(networkService.resolveBindHostAddresses(address == null ? null : new String[] { address })); + NetworkUtils.sortAddresses(addresses); + multicastChannel = MulticastChannel.getChannel(nodeName(), shared, new MulticastChannel.Config(port, group, bufferSize, ttl, - // don't use publish address, the use case for that is e.g. a firewall or proxy and - // may not even be bound to an interface on this machine! use the first bound address. - networkService.resolveBindHostAddress(address)[0], + addresses.get(0), deferToInterface), new Receiver()); } catch (Throwable t) {