Improve situation when network.host is set to wildcard (e.g. 0.0.0.0)

Users might specify something like -Des.network.host=0.0.0.0, as that
was the old default with previous versions of elasticsearch. This means
to bind to all interfaces, but it makes no sense as a publish address.

Pick a good one in this case, just like we do in other cases where
publish isn't explicitly specified and we are bound to multiple (e.g.
when configured by interface, or dns hostname with multiple addresses).
However, in this case warn the user about it: since its arbitrarily
picking the first non-loopback address like the old versions
did, thats a little too heuristical, but lets make the cutover easy.

Separately, fail hard if things like multicast or broadcast addresses are
configured as bind or publish addresses, as that is simply invalid.

Closes #13274
This commit is contained in:
Robert Muir 2015-09-02 23:03:31 -04:00
parent 2a129f1868
commit 6bdf89c47e
2 changed files with 217 additions and 3 deletions

View File

@ -22,12 +22,13 @@ package org.elasticsearch.common.network;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -110,7 +111,26 @@ public class NetworkService extends AbstractComponent {
if (bindHost == null) {
bindHost = DEFAULT_NETWORK_HOST;
}
return resolveInetAddress(bindHost);
InetAddress addresses[] = resolveInetAddress(bindHost);
// 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");
}
// check if its broadcast: flat out mistake
for (NetworkInterface nic : NetworkUtils.getInterfaces()) {
for (InterfaceAddress intf : nic.getInterfaceAddresses()) {
if (address.equals(intf.getBroadcast())) {
throw new IllegalArgumentException("bind address: {" + NetworkAddress.format(address) + "} is invalid: broadcast address");
}
}
}
}
}
return addresses;
}
// TODO: needs to be InetAddress[]
@ -133,7 +153,31 @@ public class NetworkService extends AbstractComponent {
publishHost = DEFAULT_NETWORK_HOST;
}
// TODO: allow publishing multiple addresses
return resolveInetAddress(publishHost)[0];
InetAddress address = resolveInetAddress(publishHost)[0];
// try to deal with some (mis)configuration
if (address != null) {
// check if its multicast: flat out mistake
if (address.isMulticastAddress()) {
throw new IllegalArgumentException("publish address: {" + NetworkAddress.format(address) + "} is invalid: multicast address");
}
// check if its broadcast: flat out mistake
for (NetworkInterface nic : NetworkUtils.getInterfaces()) {
for (InterfaceAddress intf : nic.getInterfaceAddresses()) {
if (address.equals(intf.getBroadcast())) {
throw new IllegalArgumentException("publish address: {" + NetworkAddress.format(address) + "} is invalid: broadcast address");
}
}
}
// wildcard address, probably set by network.host
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));
}
}
return address;
}
private InetAddress[] resolveInetAddress(String host) throws UnknownHostException, IOException {

View File

@ -0,0 +1,170 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.network;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Tests for network service... try to keep them safe depending upon configuration
* please don't actually bind to anything, just test the addresses.
*/
public class NetworkServiceTests extends ESTestCase {
/**
* ensure exception if we bind to multicast ipv4 address
*/
public void testBindMulticastV4() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
try {
service.resolveBindHostAddress("239.1.1.1");
fail("should have hit exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: multicast"));
}
}
/**
* ensure exception if we bind to multicast ipv6 address
*/
public void testBindMulticastV6() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
try {
service.resolveBindHostAddress("FF08::108");
fail("should have hit exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: multicast"));
}
}
/**
* ensure exception if we publish to multicast ipv4 address
*/
public void testPublishMulticastV4() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
try {
service.resolvePublishHostAddress("239.1.1.1");
fail("should have hit exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: multicast"));
}
}
/**
* ensure exception if we publish to multicast ipv6 address
*/
public void testPublishMulticastV6() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
try {
service.resolvePublishHostAddress("FF08::108");
fail("should have hit exception");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: multicast"));
}
}
/**
* ensure exception if we bind/publish to broadcast address
*/
public void testBindPublishBroadcast() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
// collect any broadcast addresses on the system
List<InetAddress> addresses = new ArrayList<>();
for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {
for (InterfaceAddress intf : nic.getInterfaceAddresses()) {
InetAddress address = intf.getBroadcast();
if (address != null) {
addresses.add(address);
}
}
}
// can easily happen (ipv6-only, localhost-only, ...)
assumeTrue("test requires broadcast addresses configured", addresses.size() > 0);
// make sure we fail on each one
for (InetAddress address : addresses) {
try {
service.resolveBindHostAddress(NetworkAddress.formatAddress(address));
fail("should have hit exception for broadcast address: " + address);
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: broadcast"));
}
try {
service.resolvePublishHostAddress(NetworkAddress.formatAddress(address));
fail("should have hit exception for broadcast address: " + address);
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("invalid: broadcast"));
}
}
}
/**
* ensure specifying wildcard ipv4 address will bind to all interfaces
*/
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]);
}
/**
* ensure specifying wildcard ipv6 address will bind to all interfaces
*/
public void testBindAnyLocalV6() throws Exception {
NetworkService service = new NetworkService(Settings.EMPTY);
assertEquals(InetAddress.getByName("::"), service.resolveBindHostAddress("::")[0]);
}
/**
* ensure specifying wildcard ipv4 address selects reasonable publish address
*/
public void testPublishAnyLocalV4() throws Exception {
InetAddress expected = null;
try {
expected = NetworkUtils.getFirstNonLoopbackAddresses()[0];
} catch (Exception e) {
assumeNoException("test requires up-and-running non-loopback address", e);
}
NetworkService service = new NetworkService(Settings.EMPTY);
assertEquals(expected, service.resolvePublishHostAddress("0.0.0.0"));
}
/**
* ensure specifying wildcard ipv6 address selects reasonable publish address
*/
public void testPublishAnyLocalV6() throws Exception {
InetAddress expected = null;
try {
expected = NetworkUtils.getFirstNonLoopbackAddresses()[0];
} catch (Exception e) {
assumeNoException("test requires up-and-running non-loopback address", e);
}
NetworkService service = new NetworkService(Settings.EMPTY);
assertEquals(expected, service.resolvePublishHostAddress("::"));
}
}