diff --git a/core/java/src/net/i2p/util/Addresses.java b/core/java/src/net/i2p/util/Addresses.java index 5c64c43c4..1fcdaafce 100644 --- a/core/java/src/net/i2p/util/Addresses.java +++ b/core/java/src/net/i2p/util/Addresses.java @@ -483,6 +483,9 @@ public abstract class Addresses { * Caches numeric addresses only. * Will resolve but not cache DNS addresses. * + * DEPRECATED for IPs in RouterAddresses, blocklists, etc., + * use getI2POnly() which avoids getByName() in most cases. + * * Unlike InetAddress.getByName(), we do NOT allow numeric IPs * of the form d.d.d, d.d, or d, as these are almost certainly mistakes. * @@ -512,7 +515,6 @@ public abstract class Addresses { _negativeCache.remove(host); } } - //I2PAppContext.getGlobalContext().logManager().getLog(Addresses.class).error("lookup of " + host, new Exception("I did it")); try { rv = InetAddress.getByName(host).getAddress(); if (isIPAddress(host)) { @@ -535,6 +537,9 @@ public abstract class Addresses { * Resolves literal IP addresses only, will not cause a DNS lookup. * Will return null for hostnames. * + * PREFERRED for IPs in RouterAddresses, blocklists, etc. over getI2P() + * because it avoids getByName() in most cases. + * * Unlike InetAddress.getByName(), we do NOT allow numeric IPs * of the form d.d.d, d.d, or d, as these are almost certainly mistakes. * @@ -570,8 +575,6 @@ public abstract class Addresses { _IPAddress.put(host, rv); } } catch (UnknownHostException uhe) {} - //} else { - // I2PAppContext.getGlobalContext().logManager().getLog(Addresses.class).warn("Not looking up " + host, new Exception("I did it")); } } return rv; @@ -702,14 +705,8 @@ public abstract class Addresses { return InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host); } - /** - * Because InetAddress.getByName() is slow, esp. on Windows - * - * @param host w.x.y.z only - * @return 4 bytes or null - * @since 0.9.50 - */ - private static byte[] getIPv4(String host) { +/* + private static byte[] oldGetIPv4(String host) { String[] s = DataHelper.split(host, "\\.", 4); if (s.length != 4) return null; @@ -727,14 +724,7 @@ public abstract class Addresses { return rv; } - /** - * Because InetAddress.getByName() is slow, esp. on Windows - * - * @param host full 0:1:2:3:4:5:6:7 only, no :: - * @return 16 bytes or null - * @since 0.9.50 - */ - private static byte[] getIPv6(String host) { + private static byte[] oldGetIPv6(String host) { String[] s = DataHelper.split(host, ":", 8); if (s.length != 8) return null; @@ -753,6 +743,83 @@ public abstract class Addresses { } return rv; } +*/ + + /** + * Because InetAddress.getByName() is slow, esp. on Windows. + * Also avoids split(), Integer.parseInt(), and object churn. + * + * @param host w.x.y.z only + * @return 4 bytes or null + * @since 0.9.50 + */ + private static byte[] getIPv4(String host) { + byte[] rv = new byte[4]; + int b = 0; + int dots = 0; + int len = host.length(); + for (int i = 0; i < len; i++) { + char c = host.charAt(i); + if (c == '.') { + if (i == 0 || i == len - 1 || dots == 3 || b > 255 || host.charAt(i - 1) == '.') + return null; + rv[dots++] = (byte) b; + b = 0; + } else if (c >= '0' && c <= '9') { + b *= 10; + b += c - '0'; + } else { + return null; + } + } + if (dots != 3 || b > 255) + return null; + rv[3] = (byte) b; + return rv; + } + + /** + * Because InetAddress.getByName() is slow, esp. on Windows. + * Also avoids split(), Integer.parseInt(), and object churn. + * + * @param host full 0:1:2:3:4:5:6:7 only, no :: + * @return 16 bytes or null + * @since 0.9.50 + */ + private static byte[] getIPv6(String host) { + byte[] rv = new byte[16]; + int b = 0; + int j = 0; + int colons = 0; + int len = host.length(); + for (int i = 0; i < len; i++) { + char c = host.charAt(i); + if (c == ':') { + if (i == 0 || i == len - 1 || colons == 7 || b > 65535 || host.charAt(i - 1) == ':') + return null; + rv[j++] = (byte) (b >> 8); + rv[j++] = (byte) b; + colons++; + b = 0; + } else if (c >= '0' && c <= '9') { + b <<= 4; + b |= c - '0'; + } else if (c >= 'a' && c <= 'f') { + b <<= 4; + b |= 10 + c - 'a'; + } else if (c >= 'A' && c <= 'F') { + b <<= 4; + b |= 10 + c - 'A'; + } else { + return null; + } + } + if (colons != 7 || b > 65535) + return null; + rv[14] = (byte) (b >> 8); + rv[15] = (byte) b; + return rv; + } //////// IPv6 Cache Utils /////// @@ -938,6 +1005,7 @@ public abstract class Addresses { * Print out the local addresses */ public static void main(String[] args) { + //test(); if (true) return; System.out.println("Connected Address Types: " + getConnectedAddressTypes() + '\n'); System.out.println("External IPv4 Addresses:"); Set a = getAddresses(false, false, false); @@ -1016,6 +1084,85 @@ public abstract class Addresses { System.out.println("scan time: " + DataHelper.formatDuration(time)); } +/* + // test results (linux): + // new is about 10x faster than old + // InetAddress about the same as old for IPv4, about 4x slower for IPv6 + private static void test() { + String[] tt = { "1.2.3.4", "0.0.0.0", "255.255.255.255", "", "a", "1", "1.2", "1.2.3", + ".1.2.3", "1.2.3.", "266.1.2.3", "1.266.2.3", "1.2.3.266", "1.2.3.4.5" }; + for (String t : tt) { + byte[] b = getIPv4(t); + System.out.println(t + " -> " + toString(b)); + } + tt = new String[] { "a:B:c:D:e:f:1:2", "aaaa:bbbb:CCC:dd:e:f:111:2222", "a", "1", "1:2", "1::2:3:4:5:6:7:8", + ":1:2:3:4:5:6:7", "2:3:4:5:6:7:8:", "x:2:3:4:5:6:7:8", "::1", "::", "", + "99999:2:3:4:5:6:7:8" }; + for (String t : tt) { + byte[] b = getIPv6(t); + System.out.println(t + " -> " + toString(b)); + } + int runs = 1000; + for (int i = 0; i < runs; i++) { + try { + InetAddress.getByName("192.168.142.117").getAddress(); + InetAddress.getByName("aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222").getAddress(); + } catch (Exception e) {} + oldGetIPv4("192.168.142.117"); + oldGetIPv6("aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222"); + getIPv4("192.168.142.117"); + getIPv6("aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222"); + } + runs = 10*1000*1000; + long start = System.currentTimeMillis(); + for (int i = 0; i < runs; i++) { + oldGetIPv4("192.168.142.117"); + } + long end = System.currentTimeMillis(); + System.out.println("old ipv4 took " + (end - start)); + start = end; + + for (int i = 0; i < runs; i++) { + getIPv4("192.168.142.117"); + } + end = System.currentTimeMillis(); + System.out.println("new ipv4 took " + (end - start)); + start = end; + + for (int i = 0; i < runs; i++) { + try { + InetAddress.getByName("192.168.142.117").getAddress(); + InetAddress.getByName("aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222").getAddress(); + } catch (Exception e) {} + } + end = System.currentTimeMillis(); + System.out.println("INA ipv4 took " + (end - start)); + start = end; + + for (int i = 0; i < runs; i++) { + oldGetIPv6("192.168.142.117"); + } + end = System.currentTimeMillis(); + System.out.println("old ipv6 took " + (end - start)); + start = end; + + for (int i = 0; i < runs; i++) { + getIPv6("192.168.142.117"); + } + end = System.currentTimeMillis(); + System.out.println("new ipv6 took " + (end - start)); + + for (int i = 0; i < runs; i++) { + try { + InetAddress.getByName("aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222").getAddress(); + } catch (Exception e) {} + } + end = System.currentTimeMillis(); + System.out.println("INA ipv6 took " + (end - start)); + start = end; + } +*/ + /** @since 0.9.34 */ private static void print(Set a) { if (a.isEmpty()) {