From 47881c41a989b6bc654aade00709da88e8cb40b3 Mon Sep 17 00:00:00 2001 From: Umoxfo Date: Tue, 21 Mar 2017 19:56:51 -0700 Subject: [PATCH 1/3] NET-627 Created a new package for supporting IPv6 subnet --- .../commons/net/util/subnet/package-info.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/org/apache/commons/net/util/subnet/package-info.java diff --git a/src/main/java/org/apache/commons/net/util/subnet/package-info.java b/src/main/java/org/apache/commons/net/util/subnet/package-info.java new file mode 100644 index 000000000..7f38e6da5 --- /dev/null +++ b/src/main/java/org/apache/commons/net/util/subnet/package-info.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * IPv4 and IPv6 subnet classes + */ +package org.apache.commons.net.util.subnet; \ No newline at end of file From db80d32329cdde7e925eb80ee58bbbd2eea0a4e4 Mon Sep 17 00:00:00 2001 From: Umoxfo Date: Tue, 21 Mar 2017 20:53:39 -0700 Subject: [PATCH 2/3] NET-628 Prepared an abstract class for subnet functions Followed the coding conventions of Apache Commons Net. Improved comments. --- .../commons/net/util/subnet/SubnetInfo.java | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java diff --git a/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java b/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java new file mode 100644 index 000000000..ddf44012f --- /dev/null +++ b/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.util.subnet; + +/** + * Convenience container for subnet summary information. + * @since 3.7 + */ +public abstract class SubnetInfo +{ + + /** + * Returns true if the return value of {@link #getAddressCount()} + * includes the network and broadcast addresses. (ONLY USE in IPv4) + * + * @return true if the host count includes the network and broadcast addresses + */ + public boolean isInclusiveHostCount() { return false; } + + /** + * Sets to true if you want the return value of {@link #getAddressCount()} + * to include the network and broadcast addresses. (ONLY USE in IPv4) + * + * @param inclusiveHostCount true if network and broadcast addresses are to be included + */ + public void setInclusiveHostCount(boolean inclusiveHostCount) { } + + /** + * Returns true if the parameter address is in the + * range of usable endpoint addresses for this subnet. This excludes the + * network and broadcast addresses if the address is IPv4 address. + * + * @param address a dot-delimited IPv4 address, e.g. "192.168.0.1", or + * a colon-hexadecimal IPv6 address, e.g. "2001:db8::ff00:42:8329" + * @return true if in range, false otherwise + */ + public abstract boolean isInRange(String address); + + /** + * Returns true if the parameter address is in the + * range of usable endpoint addresses for this subnet. This excludes the + * network and broadcast addresses if the address is IPv4 address. + * + * @param address the address to check + * @return true if it is in range + */ + public boolean isInRange(int address) { return false; } + + /** + * Returns true if the parameter address is in the + * range of usable endpoint addresses for this subnet. This excludes the + * network and broadcast addresses if the address is IPv4 address. + * + * @param address the address to check + * @return true if it is in range + */ + public boolean isInRange(short[] address) { return false; } + + /** + * Returns the IP address. + * IPv4 format: the dot-decimal format, e.g. "192.168.0.1" + * IPv6 format: the colon-hexadecimal format, e.g. "2001:db8::ff00:42:8329" + * + * @return a string of the IP address + */ + public abstract String getAddress(); + + /** + * Returns the CIDR suffixes, the count of consecutive 1 bits in the subnet mask. + * The range in IPv4 is 0-32, and in IPv6 is 0-128, actually 64 or less. + * + * @return the CIDR suffixes of the address in an integer. + */ + public abstract int getCIDR(); + + /** + * Returns a netmask in the address. (ONLY USE IPv4) + * + * @return a string of netmask in a dot-decimal format. + */ + public String getNetmask() { return null; } + + /** + * Returns a network address in the address. (ONLY USE IPv4) + * + * @return a string of a network address in a dot-decimal format. + */ + public String getNetworkAddress() { return null; } + + /** + * Returns a broadcast address in the address. (ONLY USE IPv4) + * + * @return a string of a broadcast address in a dot-decimal format. + */ + public String getBroadcastAddress() { return null; } + + /** + * Returns a CIDR notation, in which the address is followed by slash and + * the count of counting the 1-bit population in the subnet mask. + * IPv4 CIDR notation: e.g. "192.168.0.1/24" + * IPv6 CIDR notation: e.g. "2001:db8::ff00:42:8329/48" + * + * @return the CIDR notation of the address + */ + public String getCIDRNotation() { return null; } + + /** + * Returns the lowest address as a dotted decimal or the colon-separated hexadecimal IP address. + * Will be zero for CIDR/31 and CIDR/32 if the address is IPv4 address and + * the inclusive flag is false. + * + * @return the IP address in dotted or colon 16-bit delimited format, + * may be "0.0.0.0" or "::" if there is no valid address + */ + public String getLowAddress() { return null; } + + /** + * Returns the highest address as the dotted decimal or the colon-separated hexadecimal IP address. + * Will be zero for CIDR/31 and CIDR/32 if the address is IPv4 address and + * the inclusive flag is false. + * + * @return the IP address in dotted or colon 16-bit delimited format, + * may be "0.0.0.0" or "::" if there is no valid address + */ + public String getHighAddress() { return null; } + + /** + * Returns the count of available addresses. + * Will be zero for CIDR/31 and CIDR/32 if the address is IPv4 address and + * the inclusive flag is false. + * + * @return the count of addresses in a string, may be zero + */ + public String getAddressCount() { return null; } + + /** + * Returns the count of available addresses. + * Will be zero for CIDR/31 and CIDR/32 if the address is IPv4 address and + * the inclusive flag is false. + * + * @return the count of addresses, may be zero + */ + public long getAddressCountLong() { return 0; } + +} From 95e5f4a416a5c5e23a11837a7f4325ae5a436589 Mon Sep 17 00:00:00 2001 From: Umoxfo Date: Wed, 22 Mar 2017 02:27:18 -0700 Subject: [PATCH 3/3] NET-629 Added IP4Subnet and IP6Subnet classes in the subnet package The method rangeCheck, pop, and format of SubnetUtils was moved to SubnetInfo in the subnet package. Added asInteger, getCidrSignature, and getAllAddresses methods of SubnetUtils.SubnetInfo to SubnetInfo in the subnet package. Changed the parameter type of isInRange from short array to integer array. Improved comments --- .../commons/net/util/subnet/IP4Subnet.java | 359 ++++++++++++++++++ .../commons/net/util/subnet/IP6Subnet.java | 274 +++++++++++++ .../commons/net/util/subnet/SubnetInfo.java | 82 +++- 3 files changed, 711 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/apache/commons/net/util/subnet/IP4Subnet.java create mode 100644 src/main/java/org/apache/commons/net/util/subnet/IP6Subnet.java diff --git a/src/main/java/org/apache/commons/net/util/subnet/IP4Subnet.java b/src/main/java/org/apache/commons/net/util/subnet/IP4Subnet.java new file mode 100644 index 000000000..74fce96f4 --- /dev/null +++ b/src/main/java/org/apache/commons/net/util/subnet/IP4Subnet.java @@ -0,0 +1,359 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.util.subnet; + +/** + * Convenience container for IPv4 subnet summary information. + * @see https://tools.ietf.org/html/rfc4632 + * @since 3.7 + */ +public final class IP4Subnet extends SubnetInfo +{ + + /* Mask to convert an unsigned integer to a long (e.g. keep 32 bits) */ + private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; + private static final int NBITS = 32; + + private final int address; + private final int cidr; + private final int netmask; + private final int network; + private final int broadcast; + + /** Whether the broadcast/network addresses are included in host count */ + private boolean inclusiveHostCount = false; + + /** + * Constructor that takes CIDR-notation, e.g. "192.168.0.1/16". + * + * @param cidrNotation an IPv4 address in CIDR-notation + * @throws IllegalArgumentException if the parameter is invalid, + * e.g. does not match n.n.n.n/m where n=1-3 decimal digits, m is in range 0-32 + */ + public IP4Subnet(String cidrNotation) + { + String[] addr = cidrNotation.split("/"); + + this.address = toInteger(addr[0]); + + /* Create a network prefix, CIDR, from the number of bits specification /x */ + this.cidr = rangeCheck(Integer.parseInt(addr[1]), 0, NBITS); + + /* + * An IPv4 netmask consists of 32 bits, a contiguous sequence + * of the specified number of ones followed by all zeros. + * So, it can be obtained by shifting an unsigned integer (32 bits) to the left by + * the number of trailing zeros which is (32 - the # bits specification). + * Note that there is no unsigned left shift operator, so we have to use + * a long to ensure that the left-most bit is shifted out correctly. + */ + this.netmask = (int) (UNSIGNED_INT_MASK << (NBITS - cidr)); + + /* Calculate base network address */ + this.network = (address & netmask); + + /* Calculate broadcast address */ + this.broadcast = network | ~(netmask); + } + + /** + * Constructor that takes a dotted decimal address and a dotted decimal mask. + * + * @param address an IPv4 address, e.g. "192.168.0.1" + * @param mask a dotted decimal netmask e.g. "255.255.0.0" + * @throws IllegalArgumentException if the address or mask is invalid, + * i.e. does not match n.n.n.n where n=1-3 decimal digits and the mask is not all zeros. + */ + public IP4Subnet(String address, String mask) + { + this.address = toInteger(address); + this.netmask = toInteger(mask); + + /* + * An IPv4 subnet mask must consist of a set of contiguous 1-bits followed by a block of 0-bits. + * If the mask follows the format, the numbers of subtracting one from the lowest one bit of the mask, + * see Hacker's Delight section 2.1, equals to the bitwise complement of the mask. + */ + if ((this.netmask & -this.netmask) - 1 != ~this.netmask) + { + throw new IllegalArgumentException("Could not parse [" + mask + "]"); + } + + this.cidr = pop(this.netmask); + + /* Calculate base network address */ + this.network = (this.address & this.netmask); + + /* Calculate broadcast address */ + this.broadcast = this.network | ~(this.netmask); + } + + /** + * Returns true if the return value of {@link #getAddressCount()} + * includes the network and broadcast addresses. + * + * @return true if the host count includes the network and broadcast addresses + */ + @Override + public boolean isInclusiveHostCount() + { + return inclusiveHostCount; + } + + /** + * Sets to true if you want the return value of {@link #getAddressCount()} + * to include the network and broadcast addresses. + * + * @param inclusiveHostCount true if network and broadcast addresses are to be included + */ + @Override + public void setInclusiveHostCount(boolean inclusiveHostCount) + { + this.inclusiveHostCount = inclusiveHostCount; + } + + /* long versions of the values (as unsigned int) which are more suitable for range checking */ + private long networkLong() + { + return network & UNSIGNED_INT_MASK; + } + + private long broadcastLong() + { + return broadcast & UNSIGNED_INT_MASK; + } + + /* + * Creates the minimum address in the network to which the address belongs. + * + * inclusiveHostCount + * - true: the network address + * - false: the first address of the available as host addresses or 0 if no corresponding address + */ + private int low() + { + return inclusiveHostCount ? network : (broadcastLong() - networkLong()) > 1 ? network + 1 : 0; + } + + /* + * Creates the maximum address in the network to which the address belongs. + * + * inclusiveHostCount + * - true: the broadcast address + * - false: the last address of the available as host addresses or 0 if no corresponding address + */ + private int high() + { + return inclusiveHostCount ? broadcast : (broadcastLong() - networkLong()) > 1 ? broadcast - 1 : 0; + } + + /* + * Converts a packed integer address into dotted decimal format. + */ + private String format(int val) + { + int ret[] = new int[4]; + for (int i = 3; i >= 0; i--) + { + ret[i] = (val >>> (8 * (3 - i))) & 0xff; + } + + return SubnetInfo.format(ret, "."); + } + + /* + * Converts a dotted decimal format address to a packed integer format. + */ + private static int toInteger(String address) + { + String[] addrArry = address.split("\\."); + + // Check the length of the array, must be 4 + if (addrArry.length != 4) + { + throw new IllegalArgumentException("Could not parse [" + address + "]"); + } + + /* Check range of each element and convert to integer */ + int addr = 0; + for (int i = 0; i < 4; i++) + { + int n = rangeCheck(Integer.parseInt(addrArry[i]), 0, 255); + addr |= (n & 0xff) << (8 * (3 - i)); + } + + return addr; + } + + /** + * Returns true if the parameter address is in the + * range of usable endpoint addresses for this subnet. This excludes the + * network and broadcast addresses. + * + * @param address a dot-delimited IPv4 address, e.g. "192.168.0.1" + * @return true if in range, false otherwise + */ + @Override + public boolean isInRange(String address) + { + return isInRange(toInteger(address)); + } + + /** + * Returns true if the parameter address is in the + * range of usable endpoint addresses for this subnet. This excludes the + * network and broadcast addresses. + * + * @param address an IPv4 address in binary + * @return true if in range, false otherwise + */ + @Override + public boolean isInRange(int address) + { + long addLong = address & UNSIGNED_INT_MASK; + long netLong = networkLong(); + long broadLong = broadcastLong(); + return (addLong > netLong) && (addLong < broadLong); + } + + /** + * Returns the IPv4 address in the dotted decimal format, e.g. "192.168.0.1". + * + * @return a string of the IP address + */ + @Override + public String getAddress() + { + return format(address); + } + + /** + * Returns the CIDR suffixes, the count of consecutive 1 bits in the subnet mask + * in range of 0-32. + * + * @return the CIDR suffixes of the address in an integer. + */ + @Override + public int getCIDR() + { + return cidr; + } + + @Override + public String getNetmask() + { + return format(netmask); + } + + @Override + public String getNetworkAddress() + { + return format(network); + } + + @Override + public String getBroadcastAddress() + { + return format(broadcast); + } + + /** + * Returns a CIDR notation, in which the address is followed by slash and + * the count of counting the 1-bit population in the subnet mask, e.g. "192.168.0.1/24". + * + * @return the CIDR notation of an IPv4 address + */ + @Override + public String getCIDRNotation() + { + return format(address) + "/" + cidr; + } + + /** + * Returns the lowest address as a dotted decimal IPv4 address. + * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. + * + * @return the IP address in the dotted decimal format, may be "0.0.0.0" if there is no valid address + */ + @Override + public String getLowAddress() + { + return format(low()); + } + + /** + * Returns the highest address as a dotted decimal IPv4 address. + * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. + * + * @return the IP address in dotted decimal format, may be "0.0.0.0" if there is no valid address + */ + @Override + public String getHighAddress() + { + return format(high()); + } + + /** + * Returns the count of available addresses. + * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. + * + * @return the count of addresses in a string, may be zero + */ + @Override + public String getAddressCountString() + { + return Long.toString(getAddressCountLong()); + } + + /** + * Returns the count of available addresses. + * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. + * + * @return the count of addresses, may be zero + */ + @Override + public long getAddressCountLong() + { + long b = broadcastLong(); + long n = networkLong(); + long count = (b - n) + (inclusiveHostCount ? 1 : -1); + return count < 0 ? 0 : count; + } + + /** + * Returns subnet summary information of the address, + * which includes an IP address by CIDR-Notation with the netmask, + * network address, broadcast address, the first and last addresses of the network, + * and the number of available addresses in the network which includes + * the network and broadcast addresses if the inclusive flag is true. + */ + @Override + public String toString() + { + final StringBuilder buf = new StringBuilder(); + buf.append("CIDR-Notation:\t[").append(getCIDRNotation()).append("]") + .append(" Netmask: [").append(getNetmask()).append("]\n") + .append("Network:\t[").append(getNetworkAddress()).append("]\n") + .append("Broadcast:\t[").append(getBroadcastAddress()).append("]\n") + .append("First Address:\t[").append(getLowAddress()).append("]\n") + .append("Last Address:\t[").append(getHighAddress()).append("]\n") + .append("# Addresses:\t[").append(getAddressCountLong()).append("]\n"); + + return buf.toString(); + } + +} diff --git a/src/main/java/org/apache/commons/net/util/subnet/IP6Subnet.java b/src/main/java/org/apache/commons/net/util/subnet/IP6Subnet.java new file mode 100644 index 000000000..7b844a39b --- /dev/null +++ b/src/main/java/org/apache/commons/net/util/subnet/IP6Subnet.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.net.util.subnet; + +import java.math.BigInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Convenience container for IPv6 subnet summary information. + * @see https://tools.ietf.org/html/rfc4291#section-2.3 + * @since 3.7 + */ +public final class IP6Subnet extends SubnetInfo +{ + + private static final int NBITS = 128; + private static final String ZERO_FIELDS = "(0\\:){2,}"; + + private final int[] ip6Address; + private final int cidr; + + /** + * Constructor that takes an IPv6 address in CIDR-notation, e.g. "2001:db8:0:0:0:ff00:42:8329/48". + * + * @param cidrNotation an IPv6 address in CIDR-notation + */ + public IP6Subnet(String cidrNotation) + { + String[] tmp = cidrNotation.split("/"); + + ip6Address = toArray(tmp[0]); + cidr = rangeCheck(Integer.parseInt(tmp[1]), 0, NBITS); + } + + /* + * Creates the minimum address in the network + * to which the address belongs, it has all-zero in the host fields. + */ + private int[] low() + { + int[] addr = new int[8]; + + // Copy of the network prefix in the address + int index = cidr / 16; + for (int i = 0; i <= index; i++) + { + addr[i] = ip6Address[i]; + } + + // Set the out of the network prefix bits. + addr[index] &= (0xffff >> (cidr % 16)) ^ 0xffff; + return addr; + } + + /* + * Creates the maximum address in the network + * to which the address belongs, it has all-ones in the host fields. + */ + private int[] high() + { + int[] highAddr = new int[8]; + + // Copy of the network prefix in the address + int index = cidr / 16; + for (int i = 0; i <= index; i++) + { + highAddr[i] = ip6Address[i]; + } + + // Fill the following fields with 1-bits + for (int i = index + 1; i < 8; i++) + { + highAddr[i] = 0xffff; + } + + // Set the out of the network prefix bits + highAddr[index] |= 0xffff >> (cidr % 16); + + return highAddr; + } + + private static int[] toArray(String address) + { + int[] ret = new int[8]; + String[] addrArry = address.split(":"); + + for (int i = 0; i < addrArry.length; i++) + { + ret[i] = Integer.parseInt(addrArry[i], 16); + } + + return ret; + } + + /* + * Converts a packed integer address into the colon-separated hexadecimal format. + */ + private String format(int[] val) + { + String address = SubnetInfo.format(val, ":"); + + /* The longest run of consecutive 0 fields MUST be shortened based on RFC 5952. */ + String regex = ""; + int maxLength = 0; + + // Find the longest zero fields + Matcher match = Pattern.compile(ZERO_FIELDS).matcher(address); + while (match.find()) + { + String reg = match.group(); + int len = reg.length(); + + if (maxLength < len) + { + regex = reg; + maxLength = len; + } + } + + // Remove all leading zeroes + return address.replace(regex, ":"); + } + + /** + * Returns true if the parameter address is + * in the range of usable endpoint addresses for this subnet. + * + * @param address a colon-delimited address, e.g. "2001:db8:0:0:0:ff00:42:8329" + * @return true if in range, false otherwise + */ + @Override + public boolean isInRange(String address) + { + return isInRange(toArray(address)); + } + + /** + * Returns true if the parameter address is + * in the range of usable endpoint addresses for this subnet. + * + * @param address an IPv6 address in binary + * @return true if in range, false otherwise + */ + @Override + public boolean isInRange(int[] address) + { + int prefixSize = cidr / 16; + int[] lowAddress = low(); + int[] highAddress = high(); + + // Have the same network prefix groups + for (int i = 0; i < prefixSize; i++) + { + // Whether all 16 bits are the same values. + if (address[i] == ip6Address[i]) + { + return false; + } + } + + //The host identifier is in range between the lowest and the hightest addresses + int addr = address[prefixSize]; + int lowAddr = lowAddress[prefixSize]; + int highAddr = highAddress[prefixSize]; + + return (addr >= lowAddr) && (addr <= highAddr); + } + + /** + * Returns the address, that is the colon 16-bit delimited hexadecimal format + * for IPv6 addresses, e.g. "2001:db8::ff00:42:8329". + * + * @return a string of the IP address + */ + @Override + public String getAddress() + { + return format(ip6Address); + } + + /** + * Returns the CIDR suffixes, the count of consecutive 1-bit in the subnet mask. + * The range of IPv6 address is between 0 and 128, but it is actually less than 64. + * + * @return the CIDR suffixes of the address in an integer. + */ + @Override + public int getCIDR() + { + return cidr; + } + + /** + * Returns the IPv6-CIDR notation, in which the address is followed by a slash and + * the count of counting the 1-bit population in the subnet mask. + * + * @return the CIDR notation of the address, e.g. "2001:db8::ff00:42:8329/48" + */ + @Override + public String getCIDRNotation() + { + return format(ip6Address) + "/" + cidr; + } + + /** + * Returns the lowest address as a colon-separated IPv6 address. + * + * @return the IP address in a colon 16-bit delimited hexadecimal format, + * may be "::" if there is no valid address + */ + @Override + public String getLowAddress() + { + return format(low()); + } + + /** + * Returns the highest address as a colon-separated IPv6 address. + * + * @return the IP address in a colon 16-bit delimited hexadecimal format, + * may be "::" if there is no valid address + */ + @Override + public String getHighAddress() + { + return format(high()); + } + + /** + * Returns the count of available addresses. + * + * @return the count of addresses in a string, may be zero + */ + @Override + public String getAddressCountString() + { + return new BigInteger("2").pow(128 - cidr).toString(); + } + + /** + * Returns subnet summary information of the address, + * which includes an IP address by CIDR-Notation, the first and + * the last addresses of the network, and the number of available addresses + * in the network which includes all-zero and all-ones in the host fields, + * known as network or broadcast addresses. + */ + @Override + public String toString() + { + final StringBuilder buf = new StringBuilder(); + buf.append("CIDR-Notation:\t[").append(getCIDRNotation()).append("]") + .append("First Address:\t[").append(getLowAddress()).append("]\n") + .append("Last Address:\t[").append(getHighAddress()).append("]\n") + .append("# Addresses:\t[").append(getAddressCountString()).append("]\n"); + + return buf.toString(); + } + +} diff --git a/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java b/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java index ddf44012f..caa9135c6 100644 --- a/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java +++ b/src/main/java/org/apache/commons/net/util/subnet/SubnetInfo.java @@ -23,6 +23,63 @@ public abstract class SubnetInfo { + /* + * Convenience function to check integer boundaries. + * Checks if a value x is in the range [begin,end]. + * Returns x if it is in range, throws an exception otherwise. + */ + static int rangeCheck(int value, int begin, int end) + { + if (value < begin || value > end) + { + throw new IllegalArgumentException("Value [" + value + "] not in range ["+begin+","+end+"]"); + } + + return value; + } + + /* + * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy + * see Hacker's Delight section 5.1 + */ + static int pop(int x) + { + x = x - ((x >>> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); + x = (x + (x >>> 4)) & 0x0F0F0F0F; + x = x + (x >>> 8); + x = x + (x >>> 16); + return x & 0x3F; + } + + /* + * Converts an integer array into a decimal format separated by symbol. + */ + static String format(int[] arry, String symbol) + { + StringBuilder str = new StringBuilder(); + final int iMax = arry.length - 1; + + for (int i =0; i <= iMax; i++) + { + str.append(arry[i]); + + if (i != iMax) + { + str.append(symbol); + } + } + + return str.toString(); + } + + /** + * Converts a dotted decimal format address to a packed integer format. (ONLY USE in IPv4 + * + * @return a packed integer of a dotted decimal format address + */ + public int asInteger(String address) { return 0; } + /** * Returns true if the return value of {@link #getAddressCount()} * includes the network and broadcast addresses. (ONLY USE in IPv4) @@ -62,13 +119,12 @@ public void setInclusiveHostCount(boolean inclusiveHostCount) { } /** * Returns true if the parameter address is in the - * range of usable endpoint addresses for this subnet. This excludes the - * network and broadcast addresses if the address is IPv4 address. + * range of usable endpoint addresses for this subnet. * * @param address the address to check * @return true if it is in range */ - public boolean isInRange(short[] address) { return false; } + public boolean isInRange(int[] address) { return false; } /** * Returns the IP address. @@ -118,6 +174,16 @@ public void setInclusiveHostCount(boolean inclusiveHostCount) { } */ public String getCIDRNotation() { return null; } + /** + * Returns a CIDR notation, in which the address is followed by slash and + * the count of counting the 1-bit population in the subnet mask. + * IPv4 CIDR notation: e.g. "192.168.0.1/24" + * IPv6 CIDR notation: e.g. "2001:db8::ff00:42:8329/48" + * + * @return the CIDR notation of the address + */ + public String getCidrSignature() { return getCIDRNotation(); } + /** * Returns the lowest address as a dotted decimal or the colon-separated hexadecimal IP address. * Will be zero for CIDR/31 and CIDR/32 if the address is IPv4 address and @@ -145,7 +211,7 @@ public void setInclusiveHostCount(boolean inclusiveHostCount) { } * * @return the count of addresses in a string, may be zero */ - public String getAddressCount() { return null; } + public String getAddressCountString() { return null; } /** * Returns the count of available addresses. @@ -156,4 +222,12 @@ public void setInclusiveHostCount(boolean inclusiveHostCount) { } */ public long getAddressCountLong() { return 0; } + /** + * Returns a list of the available addresses. + * + * @return an array of the available addresses + * @deprecated (3.7) overflow if the available addresses are greater than {@code Integer.MAX_VALUE} + */ + public String[] getAllAddresses() { return new String[0]; } + }