From 28eda2ba1bb7f5b76f382274e305ad0ccec1ae72 Mon Sep 17 00:00:00 2001 From: wenshao Date: Wed, 15 Aug 2012 17:34:53 +0800 Subject: [PATCH] add http support util : IPRange --- .../druid/support/http/util/IPAddress.java | 296 +++++++++++++++++ .../druid/support/http/util/IPRange.java | 305 ++++++++++++++++++ .../bvt/support/http/util/IPRangeTest.java | 69 ++++ 3 files changed, 670 insertions(+) create mode 100644 src/main/java/com/alibaba/druid/support/http/util/IPAddress.java create mode 100644 src/main/java/com/alibaba/druid/support/http/util/IPRange.java create mode 100644 src/test/java/com/alibaba/druid/bvt/support/http/util/IPRangeTest.java diff --git a/src/main/java/com/alibaba/druid/support/http/util/IPAddress.java b/src/main/java/com/alibaba/druid/support/http/util/IPAddress.java new file mode 100644 index 0000000000..5bc0189259 --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/http/util/IPAddress.java @@ -0,0 +1,296 @@ +package com.alibaba.druid.support.http.util; + +import java.util.NoSuchElementException; + +/** + * This class represents an IP address represented by an 32 bits integer value. Dotted-decimal notation divides the + * 32-bit Internet address into four 8-bit (byte) fields and specifies the value of each field independently as a + * decimal number with the fields separated by dots :
+ *
+ * + *     10010001 . 00001010 . 00100010 . 00000011
+ *        145      + *   10         34 + *          3
+ *
+ *              + *    -> 145.10.34.3
+ *

+ *
+ * IP address are classified into three classes :
+ *
+ * class A:
+ *
+ * + *     bit#   0  1  + *              + *   7 8      + *              + *         31
+ *           + * +--+-------------------+------------------------------+
+ *           + * |0 |           + *         |     + *              + *             + * |
+ *           + * +--+-------------------+------------------------------+
+ *            + * <-- network number --> <------- host number -------->
+ *

+ *
+ * class B:
+ *
+ * + *     bit#   0  2   + *              + *       15 16   + *              + *     31
+ *           + * +--+-------------------------+------------------------+
+ *           + * |10|             + *             | + *              + *           + * |
+ *           + * +--+-------------------------+------------------------+
+ *            + * <----- network number -----> <---- host number ----->
+ *

+ *
+ * class C:
+ *
+ * + *     bit#   0   3  + *   + *              + *          23 24 + *              + *  31
+ *           + * +---+-----------------------------+-------------------+
+ *           + * |110|           + *              + *      |        + *            |
+ *           + * +---+-----------------------------+-------------------+
+ *            + * <------- network number --------> <-- host number -->
+ *

+ *
+ * + * @author Marcel Dullaart + * @version 1.0 + */ +public class IPAddress implements Cloneable { + + /** IP address */ + protected int ipAddress = 0; + + // ------------------------------------------------------------------------- + /** + * Constructor. + * + * @param ip String representation of the IP address. The format of the ip's string representation must follow the + * decimal-dotted notation xxx.xxx.xxx.xxx. + * @exception InvalidIPAddressException Throws this exception when the specified string doesn't represent a valid IP + * address. + */ + public IPAddress(String ipAddressStr) { + ipAddress = parseIPAddress(ipAddressStr); + } + + // ------------------------------------------------------------------------- + /** + * Constructor. + * + * @param ip Binary representation of the IP address. + */ + public IPAddress(int address){ + ipAddress = address; + } + + // ------------------------------------------------------------------------- + /** + * Return the integer representation of the IP address. + * + * @return The IP address. + */ + public final int getIPAddress() { + return ipAddress; + } + + // ------------------------------------------------------------------------- + /** + * Return the string representation of the IP Address following the common decimal-dotted notation xxx.xxx.xxx.xxx. + * + * @return Return the string representation of the IP address. + */ + public String toString() { + StringBuffer result = new StringBuffer(); + int temp; + + temp = ipAddress & 0x000000FF; + result.append(temp); + result.append("."); + + temp = (ipAddress >> 8) & 0x000000FF; + result.append(temp); + result.append("."); + + temp = (ipAddress >> 16) & 0x000000FF; + result.append(temp); + result.append("."); + + temp = (ipAddress >> 24) & 0x000000FF; + result.append(temp); + + return result.toString(); + } + + // ------------------------------------------------------------------------- + /** + * Check if the IP address is belongs to a Class A IP address. + * + * @return Return true if the encapsulated IP address belongs to a class A IP address, otherwise + * returne false. + */ + public final boolean isClassA() { + return (ipAddress & 0x00000001) == 0; + } + + // ------------------------------------------------------------------------- + /** + * Check if the IP address is belongs to a Class B IP address. + * + * @return Return true if the encapsulated IP address belongs to a class B IP address, otherwise + * returne false. + */ + public final boolean isClassB() { + return (ipAddress & 0x00000003) == 1; + } + + // ------------------------------------------------------------------------- + /** + * Check if the IP address is belongs to a Class C IP address. + * + * @return Return true if the encapsulated IP address belongs to a class C IP address, otherwise + * returne false. + */ + public final boolean isClassC() { + return (ipAddress & 0x00000007) == 3; + } + + // ------------------------------------------------------------------------- + /** + * Convert a decimal-dotted notation representation of an IP address into an 32 bits interger value. + * + * @param ipAddressStr Decimal-dotted notation (xxx.xxx.xxx.xxx) of the IP address. + * @return Return the 32 bits integer representation of the IP address. + * @exception InvalidIPAddressException Throws this exception if the specified IP address is not compliant to the + * decimal-dotted notation xxx.xxx.xxx.xxx. + */ + protected int parseIPAddress(String ipAddressStr) { + int result = 0; + + if (ipAddressStr == null) { + throw new IllegalArgumentException(); + } + + try { + String tmp = ipAddressStr; + + // get the 3 first numbers + int offset = 0; + for (int i = 0; i < 3; i++) { + + // get the position of the first dot + int index = tmp.indexOf("."); + + // if there is not a dot then the ip string representation is + // not compliant to the decimal-dotted notation. + if (index != -1) { + + // get the number before the dot and convert it into + // an integer. + String numberStr = tmp.substring(0, index); + int number = Integer.parseInt(numberStr); + if ((number < 0) || (number > 255)) { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } + + result += number << offset; + offset += 8; + tmp = tmp.substring(index + 1); + } else { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } + } + + // the remaining part of the string should be the last number. + if (tmp.length() > 0) { + int number = Integer.parseInt(tmp); + if ((number < 0) || (number > 255)) { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } + + result += number << offset; + ipAddress = result; + } else { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } + } catch (NoSuchElementException ex) { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid IP Address [" + ipAddressStr + "]"); + } + + return result; + } + + // ------------------------------------------------------------------------- + /** + * Compare the specified IP address to the encapsulated one. + * + * @param another The IP address to be compared. + * @return Return true if the encapsulated IP address is the same as the specified one, otherwise + * return false. + */ + public boolean equals(Object another) { + if (another instanceof IPAddress) { + return ipAddress == ((IPAddress) another).ipAddress; + } + return false; + } + + // ------------------------------------------------------------------------- + /** + * Clone the encapsulated IP address. + * + * @return Return a new object representing the encapsulated IP address. + */ + public Object clone() { + return new IPAddress(ipAddress); + } + + public static void main(String[] args) { + + System.out.println(Integer.toBinaryString(255)); + + // try {//"192.168.1.1" + // IPAddress ip = new IPAddress(Integer.toBinaryString(3)); + // System.out.println(ip.getIPAddress()); + // System.out.println(ip.toString()); + // System.out.println(ip.parseIPAddress("192.168.4.4")); + // } catch (InvalidIPAddressException e) { + // e.printStackTrace(); + // } + } +} diff --git a/src/main/java/com/alibaba/druid/support/http/util/IPRange.java b/src/main/java/com/alibaba/druid/support/http/util/IPRange.java new file mode 100644 index 0000000000..1f04cd638f --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/http/util/IPRange.java @@ -0,0 +1,305 @@ +package com.alibaba.druid.support.http.util; + +/** + * This class represents an IP Range, which are represented by an IP address and and a subnet mask. The standards + * describing modern routing protocols often refer to the extended-network-prefix-length rather than the subnet mask. + * The prefix length is equal to the number of contiguous one-bits in the traditional subnet mask. This means that + * specifying the network address 130.5.5.25 with a subnet mask of 255.255.255.0 can also be expressed as 130.5.5.25/24. + * The / notation is more compact and easier to understand than writing out the mask in its traditional + * dotted-decimal format.
+ *
+ * + *     130.5.5.25      + * 10000010 . 00000101 . 00000101 . 00011001
+ *     255.255.255.0   + * 11111111 . 11111111 . 11111111 . 00000000
+ *              + *        <--extended-network-prefix -->
+ * or
+ *     130.5.5.25/24   + * 10000010 . 00000101 . 00000101 . 00011001
+ *

+ * This class supports both standards : the extended network prefix and the subnet mask. + * + * @author Marcel Dullaart + * @version 1.0 + * @see IPAddress + */ +public class IPRange { + + /** IP address */ + private IPAddress ipAddress = null; + + /** IP subnet mask */ + private IPAddress ipSubnetMask = null; + + /** extended network prefix */ + private int extendedNetworkPrefix = 0; + + // ------------------------------------------------------------------------- + /** + * Constructor. + * + * @param ip String representation of the IP address. The two following formats are supported :
+ *
  • xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx
  • xxx.xxx.xxx.xxx/xx <- extended network prefix + * @exception InvalidIPRangeException Throws this exception when the specified string doesn't represent a valid IP + * address. + */ + public IPRange(String range){ + parseRange(range); + } + + // ------------------------------------------------------------------------- + /** + * Constructor. + * + * @param ipAddress Reference to the IP address number + * @param subnetMask Reference to the subnet mask + * @exception InvalidIPRangeException Throws this exception when the combination of the IP address and the subnet + * mask does not define a valid IP range. + * @exception InvalidIPAddressException Throws this exception if the specified IP address or subnet mask do ne + * define a valid IP number. + */ + public IPRange(IPAddress ipAddress, IPAddress subnetMask){ + if ((ipAddress == null) || (subnetMask == null)) { + throw new IllegalArgumentException(); + } + + this.ipAddress = ipAddress; + this.ipSubnetMask = subnetMask; + + extendedNetworkPrefix = computeNetworkPrefixFromMask(subnetMask); + if (extendedNetworkPrefix == -1) { + throw new IllegalArgumentException(); + } + } + + // ------------------------------------------------------------------------- + /** + * Constructor. + * + * @param ipAddress The reference on the IP address. + * @param extendedNetworkPrefix The extended network prefix (0-32). + */ + public IPRange(IPAddress ipAddress, int extendedNetworkPrefix){ + if (ipAddress == null) { + throw new IllegalArgumentException(); + } + + if ((extendedNetworkPrefix < 0) || (extendedNetworkPrefix > 32)) { + throw new IllegalArgumentException(); + } + + this.ipAddress = ipAddress; + this.extendedNetworkPrefix = extendedNetworkPrefix; + this.ipSubnetMask = computeMaskFromNetworkPrefix(extendedNetworkPrefix); + } + + // ------------------------------------------------------------------------- + /** + * Return the encapsulated IP address. + * + * @return The IP address. + */ + public final IPAddress getIPAddress() { + return ipAddress; + } + + // ------------------------------------------------------------------------- + /** + * Return the encapsulated subnet mask + * + * @return The IP range's subnet mask. + */ + public final IPAddress getIPSubnetMask() { + return ipSubnetMask; + } + + // ------------------------------------------------------------------------- + /** + * Return the extended extended network prefix. + * + * @return Return the extended network prefix. + */ + public final int getExtendedNetworkPrefix() { + return extendedNetworkPrefix; + } + + // ------------------------------------------------------------------------- + /** + * Convert the IP Range into a string representation. + * + * @return Return the string representation of the IP Address following the common format xxx.xxx.xxx.xxx/xx (IP + * address/extended network prefixs). + */ + public String toString() { + StringBuffer result = new StringBuffer(ipAddress.toString()); + result.append("/"); + result.append(extendedNetworkPrefix); + + return result.toString(); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + extendedNetworkPrefix; + result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode()); + result = prime * result + ((ipSubnetMask == null) ? 0 : ipSubnetMask.hashCode()); + return result; + } + + // ------------------------------------------------------------------------- + /** + * Compare the specified IP range to the encapsulated one. + * + * @param another The IP range to be compared. + * @return Return true if the encapsulated IP range is the same as the specified one, otherwise return + * false. + */ + public boolean equals(Object another) { + if (another instanceof IPRange) { + IPRange range = (IPRange) another; + + return (ipAddress.equals(range.getIPAddress()) && (extendedNetworkPrefix == range.extendedNetworkPrefix)); + } + return false; + } + + // ------------------------------------------------------------------------- + /** + * Parse the IP range string representation. + * + * @param range String representation of the IP range. + * @exception InvalidIPRangeException Throws this exception if the specified range is not a valid IP network range. + */ + protected void parseRange(String range) { + if (range == null) { + throw new IllegalArgumentException("Invalid IP range"); + } + + int index = range.indexOf("/"); + String subnetStr = null; + if (index == -1) { + ipAddress = new IPAddress(range); + } else { + ipAddress = new IPAddress(range.substring(0, index)); + subnetStr = range.substring(index + 1); + } + + // try to convert the remaining part of the range into a decimal + // value. + try { + if (subnetStr != null) { + extendedNetworkPrefix = Integer.parseInt(subnetStr); + if ((extendedNetworkPrefix < 0) || (extendedNetworkPrefix > 32)) { + throw new IllegalArgumentException("Invalid IP range [" + range + "]"); + } + ipSubnetMask = computeMaskFromNetworkPrefix(extendedNetworkPrefix); + } + } catch (NumberFormatException ex) { + + // the remaining part is not a valid decimal value. + // Check if it's a decimal-dotted notation. + ipSubnetMask = new IPAddress(subnetStr); + + // create the corresponding subnet decimal + extendedNetworkPrefix = computeNetworkPrefixFromMask(ipSubnetMask); + if (extendedNetworkPrefix == -1) { + throw new IllegalArgumentException("Invalid IP range [" + range + "]"); + } + } + } + + // ------------------------------------------------------------------------- + /** + * Compute the extended network prefix from the IP subnet mask. + * + * @param mask Reference to the subnet mask IP number. + * @return Return the extended network prefix. Return -1 if the specified mask cannot be converted into a extended + * prefix network. + */ + private int computeNetworkPrefixFromMask(IPAddress mask) { + + int result = 0; + int tmp = mask.getIPAddress(); + + while ((tmp & 0x00000001) == 0x00000001) { + result++; + tmp = tmp >>> 1; + } + + if (tmp != 0) { + return -1; + } + + return result; + } + + public static String toDecimalString(String inBinaryIpAddress) { + String decimalip = new String(); + String[] binary = new String[4]; + + for (int i = 0, c = 0; i < 32; i = i + 8, c++) { + binary[c] = inBinaryIpAddress.substring(i, i + 8); + int octet = Integer.parseInt(binary[c], 2); + decimalip = decimalip + Integer.toString(octet); + if (c < 3) { + decimalip = decimalip + "."; + } + } + return decimalip; + } + + // ------------------------------------------------------------------------- + /** + * Convert a extended network prefix integer into an IP number. + * + * @param prefix The network prefix number. + * @return Return the IP number corresponding to the extended network prefix. + */ + private IPAddress computeMaskFromNetworkPrefix(int prefix) { + + /* + * int subnet = 0; for (int i=0; itrue if the specified IP address is in the encapsulated IP range, otherwise return + * false. + */ + public boolean isIPAddressInRange(IPAddress address) { + if (ipSubnetMask == null) { + return this.ipAddress.equals(address); + } + + int result1 = address.getIPAddress() & ipSubnetMask.getIPAddress(); + int result2 = ipAddress.getIPAddress() & ipSubnetMask.getIPAddress(); + + return result1 == result2; + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/support/http/util/IPRangeTest.java b/src/test/java/com/alibaba/druid/bvt/support/http/util/IPRangeTest.java new file mode 100644 index 0000000000..983f12ca7a --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/support/http/util/IPRangeTest.java @@ -0,0 +1,69 @@ +package com.alibaba.druid.bvt.support.http.util; + +import junit.framework.TestCase; + +import com.alibaba.druid.support.http.util.IPAddress; +import com.alibaba.druid.support.http.util.IPRange; + +public class IPRangeTest extends TestCase { + + public void test_ipRange_0() throws Exception { + IPRange rang = new IPRange("128.242.127.0/24"); + + assertEquals("128.242.127.0", rang.getIPAddress().toString()); + assertEquals("255.255.255.0", rang.getIPSubnetMask().toString()); + + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.2"))); + + assertFalse(rang.isIPAddressInRange(new IPAddress("128.242.126.2"))); + + } + + public void test_ipRange_1() throws Exception { + IPRange rang = new IPRange("128.242.127.0/30"); + + assertEquals("128.242.127.0", rang.getIPAddress().toString()); + assertEquals("255.255.255.252", rang.getIPSubnetMask().toString()); + + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.0"))); + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.1"))); + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.2"))); + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.3"))); + + assertFalse(rang.isIPAddressInRange(new IPAddress("128.242.127.4"))); + + } + + public void test_ipRange_2() throws Exception { + IPRange rang = new IPRange("10.16.200.0/24"); + + assertTrue(rang.isIPAddressInRange(new IPAddress("10.16.200.0"))); + assertTrue(rang.isIPAddressInRange(new IPAddress("10.16.200.255"))); + + } + + public void test_ipRange_3() throws Exception { + IPRange rang = new IPRange("0.0.0.0/0"); + assertTrue(rang.isIPAddressInRange(new IPAddress("2.16.200.0"))); + + } + + public void test_ipRange_4() throws Exception { + IPRange rang = new IPRange("1.1.1.1/0"); + + assertTrue(rang.isIPAddressInRange(new IPAddress("2.16.200.0"))); + } + + public void test_ipRange_5() throws Exception { + IPRange rang = new IPRange("1.1.1.1"); + + assertTrue(rang.isIPAddressInRange(new IPAddress("1.1.1.1"))); + } + + public void test_ipRange_6() throws Exception { + IPRange rang = new IPRange("128.242.127.3"); + + assertTrue(rang.isIPAddressInRange(new IPAddress("128.242.127.3"))); + assertFalse(rang.isIPAddressInRange(new IPAddress("128.242.127.4"))); + } +}