diff --git a/Dorkbox-Util/src/dorkbox/util/NetworkUtil.java b/Dorkbox-Util/src/dorkbox/util/NetworkUtil.java new file mode 100644 index 0000000..29c2700 --- /dev/null +++ b/Dorkbox-Util/src/dorkbox/util/NetworkUtil.java @@ -0,0 +1,231 @@ +package dorkbox.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.*; +import java.util.Enumeration; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + */ +public final +class NetworkUtil { + + /** + * Returns an InetAddress object encapsulating what is most likely the machine's LAN IP address. + *

+ * This method is intended for use as a replacement of JDK method InetAddress.getLocalHost, because + * that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same + * way as regular LAN network interfaces, but the JDK InetAddress.getLocalHost method does not + * specify the algorithm used to select the address returned under such circumstances, and will often return the + * loopback address, which is not valid for network communication. Details + * here. + *

+ * This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address + * most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer + * a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the + * first site-local address if the machine has more than one), but if the machine does not hold a site-local + * address, this method will return simply the first non-loopback address found (IPv4 or IPv6). + *

+ * If this method cannot find a non-loopback address using this selection algorithm, it will fall back to + * calling and returning the result of JDK method InetAddress.getLocalHost. + *

+ * + * @throws UnknownHostException If the LAN address of the machine cannot be found. + *

+ * From: https://issues.apache.org/jira/browse/JCS-40 + */ + public static + InetAddress getLocalHost() throws UnknownHostException { + try { + InetAddress candidateAddress = null; + // Iterate all NICs (network interface cards)... + for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { + NetworkInterface iface = ifaces.nextElement(); + // Iterate all IP addresses assigned to each card... + for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { + InetAddress inetAddr = inetAddrs.nextElement(); + if (!inetAddr.isLoopbackAddress()) { + + if (inetAddr.isSiteLocalAddress()) { + // Found non-loopback site-local address. Return it immediately... + return inetAddr; + } + else if (candidateAddress == null) { + // Found non-loopback address, but not necessarily site-local. + // Store it as a candidate to be returned if site-local address is not subsequently found... + candidateAddress = inetAddr; + // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, + // only the first. For subsequent iterations, candidate will be non-null. + } + } + } + } + if (candidateAddress != null) { + // We did not find a site-local address, but we found some other non-loopback address. + // Server might have a non-site-local address assigned to its NIC (or it might be running + // IPv6 which deprecates the "site-local" concept). + // Return this non-loopback candidate address... + return candidateAddress; + } + // At this point, we did not find a non-loopback address. + // Fall back to returning whatever InetAddress.getLocalHost() returns... + InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); + if (jdkSuppliedAddress == null) { + throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); + } + return jdkSuppliedAddress; + } catch (Exception e) { + UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e); + unknownHostException.initCause(e); + throw unknownHostException; + } + } + + + /** + * This will retrieve your IP address via an HTTP server. + *

+ * NOTE: Use DnsClient.getPublicIp() instead. It's much faster and more reliable as it uses DNS. + * + * @return the public IP address if found, or null if it didn't find it + */ + @Deprecated + public static + String getPublicIpViaHttp() { + // method 1: use DNS servers + // dig +short myip.opendns.com @resolver1.opendns.com + + // method 2: use public http servers + // @formatter:off + final String websites[] = {"http://ip.dorkbox.com/", + "http://ip.javalauncher.com/", + "http://checkip.dyndns.com/", + "http://checkip.dyn.com/", + "http://curlmyip.com/", + "http://tnx.nl/ip", + "http://ipecho.net/plain", + "http://icanhazip.com/", + "http://ip.appspot.com/",}; + // @formatter:on + + // loop, since they won't always work. + for (int i = 0; i < websites.length; i++) { + try { + URL autoIP = new URL(websites[i]); + BufferedReader in = new BufferedReader(new InputStreamReader(autoIP.openStream())); + String response = in.readLine() + .trim(); + in.close(); + + Pattern pattern = Pattern.compile("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"); + Matcher matcher = pattern.matcher(response); + if (matcher.find()) { + return matcher.group() + .trim(); + } + } catch (Exception ignored) { + } + } + + return null; + } + + /** + * Tries to retrieve the IP address from the NIC. Order is ETHx -> EMx -> WLANx + * + * @return null if not found + */ + public static + InetAddress getIpAddressesFromNic() { + try { + Enumeration nets = NetworkInterface.getNetworkInterfaces(); + while (nets.hasMoreElements()) { + NetworkInterface nextElement = nets.nextElement(); + String name = nextElement.getName(); + + // we only want to use ethX addresses! + if (name.startsWith("eth")) { + Enumeration inetAddresses = nextElement.getInetAddresses(); + + while (inetAddresses.hasMoreElements()) { + InetAddress address = inetAddresses.nextElement(); + // we only support IPV4 addresses. + if (!address.isLoopbackAddress() && address instanceof Inet4Address) { + return address; + } + } + } + } + + // it didn't work with ethX, so try emX! + while (nets.hasMoreElements()) { + nets = NetworkInterface.getNetworkInterfaces(); + NetworkInterface nextElement = nets.nextElement(); + String name = nextElement.getName(); + + // we only want to use emX addresses! + if (name.startsWith("em")) { + Enumeration inetAddresses = nextElement.getInetAddresses(); + + while (inetAddresses.hasMoreElements()) { + InetAddress address = inetAddresses.nextElement(); + // we only support IPV4 addresses. + if (!address.isLoopbackAddress() && address instanceof Inet4Address) { + return address; + } + } + } + } + + // it didn't work with emX, so try enX! + while (nets.hasMoreElements()) { + nets = NetworkInterface.getNetworkInterfaces(); + NetworkInterface nextElement = nets.nextElement(); + String name = nextElement.getName(); + + // we only want to use enX addresses! + if (name.startsWith("en")) { + Enumeration inetAddresses = nextElement.getInetAddresses(); + + while (inetAddresses.hasMoreElements()) { + InetAddress address = inetAddresses.nextElement(); + // we only support IPV4 addresses. + if (!address.isLoopbackAddress() && address instanceof Inet4Address) { + return address; + } + } + } + } + + // it didn't work with ethX, so try wifi! + while (nets.hasMoreElements()) { + nets = NetworkInterface.getNetworkInterfaces(); + NetworkInterface nextElement = nets.nextElement(); + String name = nextElement.getName(); + + // we only want to use wlanX addresses! + if (name.startsWith("wlan")) { + Enumeration inetAddresses = nextElement.getInetAddresses(); + + while (inetAddresses.hasMoreElements()) { + InetAddress address = inetAddresses.nextElement(); + // we only support IPV4 addresses. + if (!address.isLoopbackAddress() && address instanceof Inet4Address) { + return address; + } + } + } + } + } catch (SocketException ignored) { + } + + return null; + } + + private + NetworkUtil() { + } +} diff --git a/Dorkbox-Util/src/dorkbox/util/Sys.java b/Dorkbox-Util/src/dorkbox/util/Sys.java index b8f51ab..d75f71e 100644 --- a/Dorkbox-Util/src/dorkbox/util/Sys.java +++ b/Dorkbox-Util/src/dorkbox/util/Sys.java @@ -19,11 +19,11 @@ import org.bouncycastle.crypto.digests.SHA256Digest; import java.io.*; import java.lang.reflect.Field; -import java.net.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; @SuppressWarnings("unused") public final @@ -689,218 +689,6 @@ class Sys { System.err.println(builder.toString()); } - /** - * Returns an InetAddress object encapsulating what is most likely the machine's LAN IP address. - *

- * This method is intended for use as a replacement of JDK method InetAddress.getLocalHost, because - * that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same - * way as regular LAN network interfaces, but the JDK InetAddress.getLocalHost method does not - * specify the algorithm used to select the address returned under such circumstances, and will often return the - * loopback address, which is not valid for network communication. Details - * here. - *

- * This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address - * most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer - * a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the - * first site-local address if the machine has more than one), but if the machine does not hold a site-local - * address, this method will return simply the first non-loopback address found (IPv4 or IPv6). - *

- * If this method cannot find a non-loopback address using this selection algorithm, it will fall back to - * calling and returning the result of JDK method InetAddress.getLocalHost. - *

- * - * @throws UnknownHostException If the LAN address of the machine cannot be found. - *

- * From: https://issues.apache.org/jira/browse/JCS-40 - */ - public static - InetAddress getLocalHostLanAddress() throws UnknownHostException { - try { - InetAddress candidateAddress = null; - // Iterate all NICs (network interface cards)... - for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { - NetworkInterface iface = ifaces.nextElement(); - // Iterate all IP addresses assigned to each card... - for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { - InetAddress inetAddr = inetAddrs.nextElement(); - if (!inetAddr.isLoopbackAddress()) { - - if (inetAddr.isSiteLocalAddress()) { - // Found non-loopback site-local address. Return it immediately... - return inetAddr; - } - else if (candidateAddress == null) { - // Found non-loopback address, but not necessarily site-local. - // Store it as a candidate to be returned if site-local address is not subsequently found... - candidateAddress = inetAddr; - // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, - // only the first. For subsequent iterations, candidate will be non-null. - } - } - } - } - if (candidateAddress != null) { - // We did not find a site-local address, but we found some other non-loopback address. - // Server might have a non-site-local address assigned to its NIC (or it might be running - // IPv6 which deprecates the "site-local" concept). - // Return this non-loopback candidate address... - return candidateAddress; - } - // At this point, we did not find a non-loopback address. - // Fall back to returning whatever InetAddress.getLocalHost() returns... - InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); - if (jdkSuppliedAddress == null) { - throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); - } - return jdkSuppliedAddress; - } catch (Exception e) { - UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e); - unknownHostException.initCause(e); - throw unknownHostException; - } - } - - - /** - * This will retrieve your IP address via an HTTP server. - *

- * NOTE: Use DnsClient.getPublicIp() instead. It's much faster and more reliable as it uses DNS. - * - * @return the public IP address if found, or null if it didn't find it - */ - @Deprecated - public static - String getPublicIpViaHttp() { - // method 1: use DNS servers - // dig +short myip.opendns.com @resolver1.opendns.com - - // method 2: use public http servers - // @formatter:off - final String websites[] = {"http://ip.dorkbox.com/", - "http://ip.javalauncher.com/", - "http://checkip.dyndns.com/", - "http://checkip.dyn.com/", - "http://curlmyip.com/", - "http://tnx.nl/ip", - "http://ipecho.net/plain", - "http://icanhazip.com/", - "http://ip.appspot.com/",}; - // @formatter:on - - // loop, since they won't always work. - for (int i = 0; i < websites.length; i++) { - try { - URL autoIP = new URL(websites[i]); - BufferedReader in = new BufferedReader(new InputStreamReader(autoIP.openStream())); - String response = in.readLine() - .trim(); - in.close(); - - Pattern pattern = Pattern.compile("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"); - Matcher matcher = pattern.matcher(response); - if (matcher.find()) { - return matcher.group() - .trim(); - } - } catch (Exception ignored) { - } - } - - return null; - } - - /** - * Tries to retrieve the IP address from the NIC. Order is ETHx -> EMx -> WLANx - * - * @return null if not found - */ - public static - InetAddress getIpAddressesFromNic() { - try { - Enumeration nets = NetworkInterface.getNetworkInterfaces(); - while (nets.hasMoreElements()) { - NetworkInterface nextElement = nets.nextElement(); - String name = nextElement.getName(); - - // we only want to use ethX addresses! - if (name.startsWith("eth")) { - Enumeration inetAddresses = nextElement.getInetAddresses(); - - while (inetAddresses.hasMoreElements()) { - InetAddress address = inetAddresses.nextElement(); - // we only support IPV4 addresses. - if (!address.isLoopbackAddress() && address instanceof Inet4Address) { - return address; - } - } - } - } - - // it didn't work with ethX, so try emX! - while (nets.hasMoreElements()) { - nets = NetworkInterface.getNetworkInterfaces(); - NetworkInterface nextElement = nets.nextElement(); - String name = nextElement.getName(); - - // we only want to use emX addresses! - if (name.startsWith("em")) { - Enumeration inetAddresses = nextElement.getInetAddresses(); - - while (inetAddresses.hasMoreElements()) { - InetAddress address = inetAddresses.nextElement(); - // we only support IPV4 addresses. - if (!address.isLoopbackAddress() && address instanceof Inet4Address) { - return address; - } - } - } - } - - // it didn't work with emX, so try enX! - while (nets.hasMoreElements()) { - nets = NetworkInterface.getNetworkInterfaces(); - NetworkInterface nextElement = nets.nextElement(); - String name = nextElement.getName(); - - // we only want to use enX addresses! - if (name.startsWith("en")) { - Enumeration inetAddresses = nextElement.getInetAddresses(); - - while (inetAddresses.hasMoreElements()) { - InetAddress address = inetAddresses.nextElement(); - // we only support IPV4 addresses. - if (!address.isLoopbackAddress() && address instanceof Inet4Address) { - return address; - } - } - } - } - - // it didn't work with ethX, so try wifi! - while (nets.hasMoreElements()) { - nets = NetworkInterface.getNetworkInterfaces(); - NetworkInterface nextElement = nets.nextElement(); - String name = nextElement.getName(); - - // we only want to use wlanX addresses! - if (name.startsWith("wlan")) { - Enumeration inetAddresses = nextElement.getInetAddresses(); - - while (inetAddresses.hasMoreElements()) { - InetAddress address = inetAddresses.nextElement(); - // we only support IPV4 addresses. - if (!address.isLoopbackAddress() && address instanceof Inet4Address) { - return address; - } - } - } - } - } catch (SocketException ignored) { - } - - return null; - } - private Sys() { }