From 507da21dd7713ca4f72502fbea93f885914cbabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Richter?= Date: Wed, 14 Sep 2011 03:41:20 +0200 Subject: [PATCH] Proxy module: support for IPv6 (#92). It should work now. If you want restrict proxy access to localhost you should change the `dm4.proxy.net.filter` setting in `./pom.xml` to `::1/128`. See ticket 92. --- .../de/deepamehta/core/util/JavaUtils.java | 69 +++++++++++---- .../core/impl/service/JavaUtilsTest.java | 85 +++++++++++++++---- .../deepamehta/plugins/proxy/ProxyPlugin.java | 5 +- 3 files changed, 125 insertions(+), 34 deletions(-) diff --git a/deepamehta-core/src/main/java/de/deepamehta/core/util/JavaUtils.java b/deepamehta-core/src/main/java/de/deepamehta/core/util/JavaUtils.java index 43fa212b5..7a4e34b80 100644 --- a/deepamehta-core/src/main/java/de/deepamehta/core/util/JavaUtils.java +++ b/deepamehta-core/src/main/java/de/deepamehta/core/util/JavaUtils.java @@ -7,7 +7,12 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.math.BigInteger; + import java.net.FileNameMap; +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.URLConnection; import java.net.URLEncoder; @@ -32,6 +37,14 @@ public static String stripHTML(String html) { return html.replaceAll("<.*?>", ""); // *? is the reluctant version of the * quantifier (which is greedy) } + public static String times(String str, int times) { + StringBuilder sb = new StringBuilder(times * str.length()); + for (int i = 0; i < times; i++) { + sb.append(str); + } + return sb.toString(); + } + // === Files === @@ -122,27 +135,53 @@ public static String encodeURIComponent(String uriComp) { // === Networking === /** - * @param inetAddress e.g. "172.68.8.12" - * @param range e.g. "172.68.8.0/24" + * @param inetAddress IPv4 or IPv6 address or a machine name, e.g. "172.68.8.12" + * @param range IPv4 or IPv6 address range in CIDR notation, e.g. "172.68.8.0/24" */ public static boolean isInRange(String inetAddress, String range) { - String[] r = range.split("/"); - int networkAddr = inetAddress(r[0]); - int networkMask = networkMask(Integer.parseInt(r[1])); - // - return ((inetAddress(inetAddress) ^ networkAddr) & networkMask) == 0; + try { + String[] r = range.split("/"); + BigInteger networkAddr = inetAddress(r[0]); + int maskNumber = Integer.parseInt(r[1]); + InetAddress addr = InetAddress.getByName(inetAddress); + BigInteger networkMask = networkMask(addr, maskNumber); + // + return inetAddress(addr).xor(networkAddr).and(networkMask).equals(BigInteger.ZERO); + } catch (Exception e) { + throw new RuntimeException("Checking IP range failed (inetAddress=\"" + inetAddress + + "\", range=\"" + range + "\"", e); + } + } + + // --- + + public static BigInteger inetAddress(String inetAddress) { + try { + return inetAddress(InetAddress.getByName(inetAddress)); + } catch (Exception e) { + throw new RuntimeException("Parsing inet address \"" + inetAddress + "\" failed", e); + } } - public static int inetAddress(String inetAddress) { - String[] a = inetAddress.split("\\."); - return (Integer.parseInt(a[0]) << 24) + - (Integer.parseInt(a[1]) << 16) + - (Integer.parseInt(a[2]) << 8) + - Integer.parseInt(a[3]); + public static BigInteger inetAddress(InetAddress inetAddress) { + return new BigInteger(1, inetAddress.getAddress()); // signum=1 (positive) + } + + // --- + + public static BigInteger networkMask(InetAddress addr, int maskNumber) { + if (addr instanceof Inet4Address) { + return networkMask(maskNumber, 32); + } else if (addr instanceof Inet6Address) { + return networkMask(maskNumber, 128); + } else { + throw new RuntimeException("Unexpected InetAddress object: " + addr.getClass().getName()); + } } - public static int networkMask(int maskNr) { - return -1 << 32 - maskNr; + public static BigInteger networkMask(int maskNumber, int size) { + String networkMask = times("1", maskNumber) + times("0", size - maskNumber); + return new BigInteger(networkMask, 2); // radix=2 (binary) } diff --git a/deepamehta-core/src/test/java/de/deepamehta/core/impl/service/JavaUtilsTest.java b/deepamehta-core/src/test/java/de/deepamehta/core/impl/service/JavaUtilsTest.java index 18d8abcd2..56c13b767 100644 --- a/deepamehta-core/src/test/java/de/deepamehta/core/impl/service/JavaUtilsTest.java +++ b/deepamehta-core/src/test/java/de/deepamehta/core/impl/service/JavaUtilsTest.java @@ -2,6 +2,8 @@ import de.deepamehta.core.util.JavaUtils; +import java.math.BigInteger; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -29,7 +31,7 @@ public void stripHTMLwithLinebreaks() { // --- @Test - public void isInRange() { + public void isInRangeIPv4() { assertTrue(JavaUtils.isInRange("172.68.8.0", "172.68.8.0/24")); assertTrue(JavaUtils.isInRange("172.68.8.12", "172.68.8.0/24")); assertTrue(JavaUtils.isInRange("172.68.8.255", "172.68.8.0/24")); @@ -42,24 +44,73 @@ public void isInRange() { } @Test - public void inetAddress() { - assertEquals( 0, JavaUtils.inetAddress("0.0.0.0")); - assertEquals( 1, JavaUtils.inetAddress("0.0.0.1")); - assertEquals(256, JavaUtils.inetAddress("0.0.1.0")); - assertEquals((int) Math.pow(2, 24) - 1, JavaUtils.inetAddress("0.255.255.255")); - assertEquals((int) (Math.pow(2, 31) - 1), JavaUtils.inetAddress("127.255.255.255")); - assertEquals((int) -Math.pow(2, 31), JavaUtils.inetAddress("128.0.0.0")); - assertEquals(-1, JavaUtils.inetAddress("255.255.255.255")); + public void inetAddressIPv4() { + assertEquals(BigInteger.ZERO, JavaUtils.inetAddress("0.0.0.0")); + assertEquals(BigInteger.ONE, JavaUtils.inetAddress("0.0.0.1")); + assertEquals(bigInt(256), JavaUtils.inetAddress("0.0.1.0")); + assertEquals(bigInt(Math.pow(2, 24) - 1), JavaUtils.inetAddress("0.255.255.255")); + assertEquals(bigInt(Math.pow(2, 31) - 1), JavaUtils.inetAddress("127.255.255.255")); + assertEquals(bigInt(Math.pow(2, 31)), JavaUtils.inetAddress("128.0.0.0")); + assertEquals(bigInt(Math.pow(2, 32) - 1), JavaUtils.inetAddress("255.255.255.255")); + } + + @Test + public void networkMaskIPv4() { + assertEquals(JavaUtils.inetAddress("0.0.0.0"), JavaUtils.networkMask(0, 32)); + assertEquals(JavaUtils.inetAddress("128.0.0.0"), JavaUtils.networkMask(1, 32)); + assertEquals(JavaUtils.inetAddress("255.0.0.0"), JavaUtils.networkMask(8, 32)); + assertEquals(JavaUtils.inetAddress("255.255.0.0"), JavaUtils.networkMask(16, 32)); + assertEquals(JavaUtils.inetAddress("255.255.255.0"), JavaUtils.networkMask(24, 32)); + assertEquals(JavaUtils.inetAddress("255.255.255.192"), JavaUtils.networkMask(26, 32)); + assertEquals(JavaUtils.inetAddress("255.255.255.255"), JavaUtils.networkMask(32, 32)); + } + + // --- + + @Test + public void isInRangeIPv6() { + assertTrue(JavaUtils.isInRange("::3afe:7a0:c800", "::3afe:7a0:c800/120")); + assertTrue(JavaUtils.isInRange("::3afe:7a0:c880", "::3afe:7a0:c800/120")); + assertTrue(JavaUtils.isInRange("::3afe:7a0:c8ff", "::3afe:7a0:c800/120")); + assertTrue(JavaUtils.isInRange("::3afe:7a0:c800", "::3afe:7a0:c800/121")); + assertTrue(JavaUtils.isInRange("::3afe:7a0:c87f", "::3afe:7a0:c800/121")); + assertFalse(JavaUtils.isInRange("::3afe:7a0:c880", "::3afe:7a0:c800/121")); + assertFalse(JavaUtils.isInRange("::3afe:7a0:c8ff", "::3afe:7a0:c800/121")); + } + + @Test + public void inetAddressIPv6() { + assertEquals(BigInteger.ZERO, JavaUtils.inetAddress("::")); + assertEquals(BigInteger.ONE, JavaUtils.inetAddress("::1")); + assertEquals(bigInt(256), JavaUtils.inetAddress("::100")); + assertEquals(bigInt(Math.pow(2, 24) - 1), JavaUtils.inetAddress("::ff:ffff")); + assertEquals(bigInt(Math.pow(2, 31) - 1), JavaUtils.inetAddress("::7fff:ffff")); + assertEquals(bigInt(Math.pow(2, 31)), JavaUtils.inetAddress("::8000:0000")); + assertEquals(bigInt(Math.pow(2, 32) - 1), JavaUtils.inetAddress("::ffff:ffff")); + assertEquals(bigInt(Math.pow(2, 32)), JavaUtils.inetAddress("::1:0000:0000")); + assertEquals(bigInt(Math.pow(2, 63) - 1), JavaUtils.inetAddress("::7fff:ffff:ffff:ffff")); } @Test - public void networkMask() { - assertEquals(JavaUtils.inetAddress("255.255.255.255"), JavaUtils.networkMask(0)); - assertEquals(JavaUtils.inetAddress("128.0.0.0"), JavaUtils.networkMask(1)); - assertEquals(JavaUtils.inetAddress("255.0.0.0"), JavaUtils.networkMask(8)); - assertEquals(JavaUtils.inetAddress("255.255.0.0"), JavaUtils.networkMask(16)); - assertEquals(JavaUtils.inetAddress("255.255.255.0"), JavaUtils.networkMask(24)); - assertEquals(JavaUtils.inetAddress("255.255.255.192"), JavaUtils.networkMask(26)); - assertEquals(JavaUtils.inetAddress("255.255.255.255"), JavaUtils.networkMask(32)); + public void networkMaskIPv6() { + assertEquals(JavaUtils.inetAddress("::"), JavaUtils.networkMask(0, 128)); + assertEquals(JavaUtils.inetAddress("8000::"), JavaUtils.networkMask(1, 128)); + assertEquals(JavaUtils.inetAddress("ff00::"), JavaUtils.networkMask(8, 128)); + assertEquals(JavaUtils.inetAddress("ffff::"), JavaUtils.networkMask(16, 128)); + assertEquals(JavaUtils.inetAddress("ffff:ff00::"), JavaUtils.networkMask(24, 128)); + assertEquals(JavaUtils.inetAddress("ffff:ffc0::"), JavaUtils.networkMask(26, 128)); + assertEquals(JavaUtils.inetAddress("ffff:ffff::"), JavaUtils.networkMask(32, 128)); + assertEquals(JavaUtils.inetAddress("ffff:ffff:ffff:ffff::"), JavaUtils.networkMask(64, 128)); + assertEquals(JavaUtils.inetAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), JavaUtils.networkMask(128, 128)); + } + + // --- + + private BigInteger bigInt(double val) { + return bigInt((long) val); + } + + private BigInteger bigInt(long val) { + return new BigInteger(Long.toString(val)); } } diff --git a/deepamehta-proxy/src/main/java/de/deepamehta/plugins/proxy/ProxyPlugin.java b/deepamehta-proxy/src/main/java/de/deepamehta/plugins/proxy/ProxyPlugin.java index 31dfc686e..e51c6eda4 100644 --- a/deepamehta-proxy/src/main/java/de/deepamehta/plugins/proxy/ProxyPlugin.java +++ b/deepamehta-proxy/src/main/java/de/deepamehta/plugins/proxy/ProxyPlugin.java @@ -101,8 +101,9 @@ private void checkRemoteAccess(HttpServletRequest request) { String remoteAddr = request.getRemoteAddr(); boolean isInRange = JavaUtils.isInRange(remoteAddr, REMOTE_ACCESS_FILTER); // - logger.info("Checking remote access to \"" + request.getRequestURL() + "\"\n remote address=\"" + - remoteAddr + "\", range=\"" + REMOTE_ACCESS_FILTER + "\" => " + (isInRange ? "ALLOWED" : "FORBIDDEN")); + logger.info("Checking remote access to \"" + request.getRequestURL() + "\"\n dm4.proxy.net.filter=\"" + + REMOTE_ACCESS_FILTER + "\", remote address=\"" + remoteAddr + "\" => " + + (isInRange ? "ALLOWED" : "FORBIDDEN")); // if (!isInRange) { throw new WebApplicationException(Status.FORBIDDEN);