-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow binding to multiple addresses. #13954
Changes from all commits
6bc77f5
b4ba067
af8e711
11b1fa2
b9cbd7f
d7babe4
5c9a4de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,9 @@ | |
|
||
import java.io.IOException; | ||
import java.net.InetAddress; | ||
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; | ||
|
@@ -90,13 +93,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) { | ||
|
@@ -105,31 +116,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. | ||
* <p> | ||
* If {@code publishHosts} resolves to more than one address, <b>then one is selected with magic</b>, | ||
* 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It still returns a single address so its probably wrong to rename it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is only for now. I plan to solve the "multiple publish addresses" in a followup... but the api must be correct! This method takes as input, an array of addresses. and lots of places were passing |
||
// 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) { | ||
|
@@ -138,30 +162,59 @@ 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: expand to all interface addresses. | ||
if (addresses.length == 1 && addresses[0].isAnyLocalAddress()) { | ||
HashSet<InetAddress> all = new HashSet<>(Arrays.asList(NetworkUtils.getAllAddresses())); | ||
addresses = all.toArray(new InetAddress[all.size()]); | ||
} | ||
|
||
// 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<InetAddress> 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 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<InetAddress> 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 IOException { | ||
/** resolves a single host specification */ | ||
private InetAddress[] resolveInternal(String host) throws IOException { | ||
if ((host.startsWith("#") && host.endsWith("#")) || (host.startsWith("_") && host.endsWith("_"))) { | ||
host = host.substring(1, host.length() - 1); | ||
// allow custom resolvers to have special names | ||
|
@@ -178,12 +231,18 @@ private InetAddress[] resolveInetAddress(String host) throws IOException { | |
return NetworkUtils.filterIPV4(NetworkUtils.getLoopbackAddresses()); | ||
case "local:ipv6": | ||
return NetworkUtils.filterIPV6(NetworkUtils.getLoopbackAddresses()); | ||
case "non_loopback": | ||
return NetworkUtils.getFirstNonLoopbackAddresses(); | ||
case "non_loopback:ipv4": | ||
return NetworkUtils.filterIPV4(NetworkUtils.getFirstNonLoopbackAddresses()); | ||
case "non_loopback:ipv6": | ||
return NetworkUtils.filterIPV6(NetworkUtils.getFirstNonLoopbackAddresses()); | ||
case "site": | ||
return NetworkUtils.getSiteLocalAddresses(); | ||
case "site:ipv4": | ||
return NetworkUtils.filterIPV4(NetworkUtils.getSiteLocalAddresses()); | ||
case "site:ipv6": | ||
return NetworkUtils.filterIPV6(NetworkUtils.getSiteLocalAddresses()); | ||
case "global": | ||
return NetworkUtils.getGlobalAddresses(); | ||
case "global:ipv4": | ||
return NetworkUtils.filterIPV4(NetworkUtils.getGlobalAddresses()); | ||
case "global:ipv6": | ||
return NetworkUtils.filterIPV6(NetworkUtils.getGlobalAddresses()); | ||
default: | ||
/* an interface specification */ | ||
if (host.endsWith(":ipv4")) { | ||
|
@@ -197,6 +256,6 @@ private InetAddress[] resolveInetAddress(String host) throws IOException { | |
} | ||
} | ||
} | ||
return NetworkUtils.getAllByName(host); | ||
return InetAddress.getAllByName(host); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it become DEFAULT_NETWORK_HOSTS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our default is a single host specification:
_local_
. One point of this change is that you can use multiple: e.g._local_,12.1.4.2,foo.bar.com
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah - I suppose that is fine reasoning.