Improve localhost / local interface detection mechanism in NetUtil
- Do not attempt to validate localhost by binding a socket because it can fail when SecurityManager is in use - Find loopback interface first and get address from there instead of getting loopback address from InetAddress.getLocalHost() (because it's more reliable) - Instead of throwing an Error, just log and fall back to 127.0.0.1 while determining localhost address
This commit is contained in:
parent
b5989e2449
commit
656d7ca054
@ -15,17 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.util;
|
package io.netty.util;
|
||||||
|
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
@ -66,75 +63,84 @@ public final class NetUtil {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
//Start the process of discovering localhost
|
// Find the first loopback interface available.
|
||||||
InetAddress localhost;
|
NetworkInterface loopbackIface = null;
|
||||||
try {
|
try {
|
||||||
localhost = InetAddress.getLocalHost();
|
for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
|
||||||
validateHost(localhost);
|
ifaces.hasMoreElements();) {
|
||||||
} catch (IOException e0) {
|
|
||||||
// The default local host names did not work. Try hard-coded IPv4 address.
|
NetworkInterface iface = ifaces.nextElement();
|
||||||
|
if (iface.isLoopback()) {
|
||||||
|
// Found
|
||||||
|
loopbackIface = iface;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loopbackIface == null) {
|
||||||
|
logger.warn("Failed to find the loopback interface");
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
logger.warn("Failed to find the loopback interface", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOOPBACK_IF = loopbackIface;
|
||||||
|
|
||||||
|
// Find the localhost address
|
||||||
|
InetAddress localhost = null;
|
||||||
|
if (LOOPBACK_IF != null) {
|
||||||
|
logger.debug("Loopback interface: {}", LOOPBACK_IF.getDisplayName());
|
||||||
|
for (Enumeration<InetAddress> addrs = LOOPBACK_IF.getInetAddresses();
|
||||||
|
addrs.hasMoreElements();) {
|
||||||
|
InetAddress a = addrs.nextElement();
|
||||||
|
if (localhost == null) {
|
||||||
|
logger.debug("Loopback address: {} (primary)", a);
|
||||||
|
localhost = a;
|
||||||
|
} else {
|
||||||
|
logger.debug("Loopback address: {}", a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localhost == null) {
|
||||||
|
InetAddress localhost6 = null;
|
||||||
try {
|
try {
|
||||||
localhost = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
|
localhost6 = InetAddress.getByAddress(new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 });
|
||||||
validateHost(localhost);
|
} catch (Exception e) {
|
||||||
} catch (IOException e1) {
|
// We should not get here as long as the length of the address is correct.
|
||||||
// The hard-coded IPv4 address did not work. Try hard coded IPv6 address.
|
PlatformDependent.throwException(e);
|
||||||
try {
|
}
|
||||||
localhost = InetAddress.getByAddress(new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 });
|
|
||||||
validateHost(localhost);
|
try {
|
||||||
} catch (IOException e2) {
|
if (NetworkInterface.getByInetAddress(localhost6) != null) {
|
||||||
// Log all exceptions we caught so far for easier diagnosis.
|
logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
|
||||||
logger.warn("Failed to resolve localhost with InetAddress.getLocalHost():", e0);
|
localhost = localhost6;
|
||||||
logger.warn("Failed to resolve localhost with InetAddress.getByAddress(127.0.0.1):", e1);
|
}
|
||||||
logger.warn("Failed to resolve localhost with InetAddress.getByAddress(::1)", e2);
|
} catch (Exception e) {
|
||||||
throw new Error("failed to resolve localhost; incorrect network configuration?");
|
// Ignore
|
||||||
|
} finally {
|
||||||
|
if (localhost == null) {
|
||||||
|
InetAddress localhost4 = null;
|
||||||
|
try {
|
||||||
|
localhost4 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
|
||||||
|
} catch (Exception e) {
|
||||||
|
// We should not get here as long as the length of the address is correct.
|
||||||
|
PlatformDependent.throwException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
|
||||||
|
localhost = localhost4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCALHOST = localhost;
|
LOCALHOST = localhost;
|
||||||
|
|
||||||
//Prepare to get the local NetworkInterface
|
|
||||||
NetworkInterface loopbackInterface;
|
|
||||||
|
|
||||||
try {
|
|
||||||
//Automatically get the loopback interface
|
|
||||||
loopbackInterface = NetworkInterface.getByInetAddress(LOCALHOST);
|
|
||||||
} catch (SocketException e) {
|
|
||||||
//No? Alright. There is a backup!
|
|
||||||
loopbackInterface = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check to see if a network interface was not found
|
|
||||||
if (loopbackInterface == null) {
|
|
||||||
try {
|
|
||||||
//Start iterating over all network interfaces
|
|
||||||
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
|
||||||
interfaces.hasMoreElements();) {
|
|
||||||
//Get the "next" interface
|
|
||||||
NetworkInterface networkInterface = interfaces.nextElement();
|
|
||||||
|
|
||||||
//Check to see if the interface is a loopback interface
|
|
||||||
if (networkInterface.isLoopback()) {
|
|
||||||
//Phew! The loopback interface was found.
|
|
||||||
loopbackInterface = networkInterface;
|
|
||||||
//No need to keep iterating
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SocketException e) {
|
|
||||||
//Nope. Can't do anything else, sorry!
|
|
||||||
logger.warn("Failed to enumerate network interfaces", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Set the loopback interface constant
|
|
||||||
LOOPBACK_IF = loopbackInterface;
|
|
||||||
|
|
||||||
int somaxconn = 3072;
|
int somaxconn = 3072;
|
||||||
BufferedReader in = null;
|
BufferedReader in = null;
|
||||||
try {
|
try {
|
||||||
in = new BufferedReader(new FileReader("/proc/sys/net/core/somaxconn"));
|
in = new BufferedReader(new FileReader("/proc/sys/net/core/somaxconn"));
|
||||||
somaxconn = Integer.parseInt(in.readLine());
|
somaxconn = Integer.parseInt(in.readLine());
|
||||||
|
logger.debug("/proc/sys/net/core/somaxconn: {}", somaxconn);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Failed to get SOMAXCONN
|
// Failed to get SOMAXCONN
|
||||||
} finally {
|
} finally {
|
||||||
@ -150,51 +156,14 @@ public final class NetUtil {
|
|||||||
SOMAXCONN = somaxconn;
|
SOMAXCONN = somaxconn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateHost(InetAddress host) throws IOException {
|
|
||||||
ServerSocket ss = null;
|
|
||||||
Socket s1 = null;
|
|
||||||
Socket s2 = null;
|
|
||||||
try {
|
|
||||||
ss = new ServerSocket();
|
|
||||||
ss.setReuseAddress(false);
|
|
||||||
ss.bind(new InetSocketAddress(host, 0));
|
|
||||||
s1 = new Socket(host, ss.getLocalPort());
|
|
||||||
s2 = ss.accept();
|
|
||||||
} finally {
|
|
||||||
if (s2 != null) {
|
|
||||||
try {
|
|
||||||
s2.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s1 != null) {
|
|
||||||
try {
|
|
||||||
s1.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ss != null) {
|
|
||||||
try {
|
|
||||||
ss.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an byte[] based on an ipAddressString. No error handling is
|
* Creates an byte[] based on an ipAddressString. No error handling is
|
||||||
* performed here.
|
* performed here.
|
||||||
*/
|
*/
|
||||||
public static byte[] createByteArrayFromIpAddressString(
|
public static byte[] createByteArrayFromIpAddressString(String ipAddressString) {
|
||||||
String ipAddressString) {
|
|
||||||
|
|
||||||
if (isValidIpV4Address(ipAddressString)) {
|
if (isValidIpV4Address(ipAddressString)) {
|
||||||
StringTokenizer tokenizer = new StringTokenizer(ipAddressString,
|
StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ".");
|
||||||
".");
|
|
||||||
String token;
|
String token;
|
||||||
int tempInt;
|
int tempInt;
|
||||||
byte[] byteAddress = new byte[4];
|
byte[] byteAddress = new byte[4];
|
||||||
|
Loading…
Reference in New Issue
Block a user