From f5a08961f6f1a7935e2b1c01bc34ad0c3b6b225e Mon Sep 17 00:00:00 2001 From: nathan Date: Sat, 6 Sep 2014 02:41:54 +0200 Subject: [PATCH] Added DNS client. Added better localHost IP address. Added getPublicIp address via DNS and HTTP. Updated licenses --- Dorkbox-Util/LICENSE.TXT | 6 ++ Dorkbox-Util/src/dorkbox/util/Sys.java | 128 ++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/Dorkbox-Util/LICENSE.TXT b/Dorkbox-Util/LICENSE.TXT index 5a460bb..f99039f 100644 --- a/Dorkbox-Util/LICENSE.TXT +++ b/Dorkbox-Util/LICENSE.TXT @@ -80,6 +80,12 @@ Legal: + - LAN HostDiscovery from Apache Commons JCS - Apache 2.0 license + https://issues.apache.org/jira/browse/JCS-40 + Copyright 2001-2014 The Apache Software Foundation. + + + - MathUtils, IntArray, IntMap - Apache 2.0 license http://github.com/libgdx/libgdx/ Copyright (c) 2013 diff --git a/Dorkbox-Util/src/dorkbox/util/Sys.java b/Dorkbox-Util/src/dorkbox/util/Sys.java index ec57182..eec30d6 100644 --- a/Dorkbox-Util/src/dorkbox/util/Sys.java +++ b/Dorkbox-Util/src/dorkbox/util/Sys.java @@ -1,17 +1,22 @@ package dorkbox.util; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.net.InetAddress; import java.net.JarURLConnection; +import java.net.NetworkInterface; import java.net.URL; import java.net.URLConnection; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; @@ -19,6 +24,8 @@ import java.util.LinkedList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.bouncycastle.crypto.digests.SHA256Digest; @@ -520,7 +527,9 @@ public class Sys { int mod = 40; int comma = length-1; - StringBuilder builder = new StringBuilder(length + length/mod); + StringBuilder builder = new StringBuilder(length + length/mod + 2); + builder.append("{"); + for (int i = 0; i < length; i++) { builder.append(bytes[i]); if (i < comma) { @@ -531,6 +540,7 @@ public class Sys { } } + builder.append("}"); System.err.println(builder.toString()); } @@ -700,4 +710,120 @@ public class Sys { return isValid; } + + /** + * 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 more reliable as it uses DNS. + * + * @return the public IP address if found, or null if it didn't find it + */ + public static String getPublicIpViaHttp() { + // method 1: use DNS servers + // dig +short myip.opendns.com @resolver1.opendns.com + + // method 2: use public http servers + 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/", + }; + + // loop, since they won't always work. + for (int i=0;i